package com.engine.salary.biz;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.api.formmode.mybatis.util.SqlProxyHandle;
import com.engine.common.util.ServiceUtil;
import com.engine.core.impl.Service;
import com.engine.salary.cache.SalaryCacheKey;
import com.engine.salary.constant.SalaryDefaultTenantConstant;
import com.engine.salary.encrypt.EncryptUtil;
import com.engine.salary.entity.progress.ProgressDTO;
import com.engine.salary.entity.siaccount.dto.InsuranceAccountViewListDTO;
import com.engine.salary.entity.siaccount.dto.SIAccountUtilDTO;
import com.engine.salary.entity.siaccount.param.*;
import com.engine.salary.entity.siaccount.po.*;
import com.engine.salary.entity.siarchives.po.*;
import com.engine.salary.entity.sicategory.po.ICategoryPO;
import com.engine.salary.entity.sischeme.po.InsuranceSchemeDetailPO;
import com.engine.salary.entity.taxagent.po.TaxAgentPO;
import com.engine.salary.enums.siaccount.*;
import com.engine.salary.enums.sicategory.*;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.mapper.siaccount.*;
import com.engine.salary.mapper.siarchives.FundSchemeMapper;
import com.engine.salary.mapper.siarchives.InsuranceBaseInfoMapper;
import com.engine.salary.mapper.siarchives.OtherSchemeMapper;
import com.engine.salary.mapper.siarchives.SocialSchemeMapper;
import com.engine.salary.mapper.sicategory.ICategoryMapper;
import com.engine.salary.mapper.sischeme.InsuranceSchemeDetailMapper;
import com.engine.salary.mapper.taxagent.TaxAgentMapper;
import com.engine.salary.service.ProgressService;
import com.engine.salary.service.SalaryEmployeeService;
import com.engine.salary.service.TaxAgentService;
import com.engine.salary.service.impl.ProgressServiceImpl;
import com.engine.salary.service.impl.SalaryEmployeeServiceImpl;
import com.engine.salary.service.impl.TaxAgentServiceImpl;
import com.engine.salary.sys.constant.SalarySysConstant;
import com.engine.salary.sys.entity.po.SalarySysConfPO;
import com.engine.salary.sys.entity.vo.OrderRuleVO;
import com.engine.salary.sys.enums.SalaryAcctEmployeeRuleEnum;
import com.engine.salary.sys.service.SalarySysConfService;
import com.engine.salary.sys.service.impl.SalarySysConfServiceImpl;
import com.engine.salary.util.SalaryAssert;
import com.engine.salary.util.SalaryDateUtil;
import com.engine.salary.util.SalaryEntityUtil;
import com.engine.salary.util.SalaryI18nUtil;
import com.engine.salary.util.db.IdGenerator;
import com.engine.salary.util.db.MapperProxyFactory;
import com.engine.salary.util.page.PageInfo;
import com.engine.salary.util.page.SalaryPageUtil;
import com.engine.salary.util.valid.ValidUtil;
import com.google.common.collect.Lists;
import com.wbi.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import weaver.hrm.User;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @Author weaver_cl
 * @Description:
 * @Date 2022/4/11
 * @Version V1.0
 **/
@Slf4j
public class SIAccountBiz extends Service {

    private SIArchivesBiz siArchivesBiz = new SIArchivesBiz();

    private EncryptUtil encryptUtil = new EncryptUtil();

    private TaxAgentService getTaxAgentService() {
        return ServiceUtil.getService(TaxAgentServiceImpl.class, user);
    }

    private SalaryEmployeeService getSalaryEmployeeService() {
        return ServiceUtil.getService(SalaryEmployeeServiceImpl.class, user);
    }

    private InsuranceAccountBatchMapper getInsuranceAccountBatchMapper() {
        return SqlProxyHandle.getProxy(InsuranceAccountBatchMapper.class);
    }


    private InsuranceAccountDetailMapper getInsuranceAccountDetailMapper() {
        return SqlProxyHandle.getProxy(InsuranceAccountDetailMapper.class);
    }

    private SIAccountUtilMapper getSIAccountUtilMapper() {
        return MapperProxyFactory.getProxy(SIAccountUtilMapper.class);
    }

    private InsuranceAccountInspectMapper getInsuranceAccountInspectMapper() {
        return MapperProxyFactory.getProxy(InsuranceAccountInspectMapper.class);
    }

    private InsuranceBaseInfoMapper getInsuranceBaseInfoMapper() {
        return MapperProxyFactory.getProxy(InsuranceBaseInfoMapper.class);
    }

    private SocialSchemeMapper getSocialSchemeMapper() {
        return MapperProxyFactory.getProxy(SocialSchemeMapper.class);
    }

    private FundSchemeMapper getFundSchemeMapper() {
        return MapperProxyFactory.getProxy(FundSchemeMapper.class);
    }

    private OtherSchemeMapper getOtherSchemeMapper() {
        return MapperProxyFactory.getProxy(OtherSchemeMapper.class);
    }

    private SalarySysConfService getSalarySysConfService(User user) {
        return  ServiceUtil.getService(SalarySysConfServiceImpl.class, user);
    }

    private InsuranceCompensationMapper getInsuranceCompensationMapper() {
        return MapperProxyFactory.getProxy(InsuranceCompensationMapper.class);
    }

    private ProgressService getSalaryAcctProgressService(User user) {
        return (ProgressService) ServiceUtil.getService(ProgressServiceImpl.class, user);
    }

    private SalaryEmployeeService getSalaryEmployeeService(User user) {
        return ServiceUtil.getService(SalaryEmployeeServiceImpl.class, user);
    }


    private SIAccountDetailTempMapper getSIAccountDetailTempMapper() {
        return MapperProxyFactory.getProxy(SIAccountDetailTempMapper.class);
    }

    private InsuranceSchemeDetailMapper getInsuranceSchemeDetailMapper() {
        return MapperProxyFactory.getProxy(InsuranceSchemeDetailMapper.class);
    }

    private ICategoryMapper getICategoryMapper() {
        return MapperProxyFactory.getProxy(ICategoryMapper.class);
    }

    private TaxAgentMapper getTaxAgentMapper() {
        return MapperProxyFactory.getProxy(TaxAgentMapper.class);
    }

    public PageInfo<InsuranceAccountBatchPO> listPage(InsuranceAccountBatchParam queryParam) {
        List<InsuranceAccountBatchPO> list = getInsuranceAccountBatchMapper().list(queryParam);
        PageInfo<InsuranceAccountBatchPO> page = SalaryPageUtil.buildPage(queryParam.getCurrent(), queryParam.getPageSize(),
                list, InsuranceAccountBatchPO.class);
        encryptUtil.decryptList(page.getList(), InsuranceAccountBatchPO.class);
        return page;
    }

    public PageInfo<InsuranceAccountDetailPO> listCommonPage(InsuranceAccountDetailParam queryParam) {
        queryParam.setPaymentStatus(PaymentStatusEnum.COMMON.getValue());

//        //过滤出需要核算的人员，即福利档案基础信息表中runStatus为正在缴纳和待减员的人员
//        List<InsuranceArchivesBaseInfoPO> baseInfoPOList = getInsuranceBaseInfoMapper().listAll();
//        List<Long> canAccountIds = baseInfoPOList.stream()
//                .filter(f->f.getPaymentOrganization().toString().equals(queryParam.getPaymentOrganization())
//                        && (f.getRunStatus().equals(EmployeeStatusEnum.PAYING.getValue()) || f.getRunStatus().equals(EmployeeStatusEnum.STAY_DEL.getValue())))
//                .map(InsuranceArchivesBaseInfoPO::getEmployeeId)
//                .collect(Collectors.toList());
//        queryParam.setEmployeeIds(canAccountIds);
        //排序配置
        OrderRuleVO orderRule = getSalarySysConfService(user).orderRule();
        queryParam.setOrderRule(orderRule);

        //系统人员福利台账明细
        List<InsuranceAccountDetailPO> list = getInsuranceAccountDetailMapper().list(queryParam);
        //非系统各人员台账明细
        List<InsuranceAccountDetailPO> extList = getInsuranceAccountDetailMapper().extList(queryParam);
        list.addAll(extList);

        PageInfo<InsuranceAccountDetailPO> pageInfo = SalaryPageUtil.buildPage(queryParam.getCurrent(), queryParam.getPageSize(),
                list, InsuranceAccountDetailPO.class);
        encryptUtil.decryptList(pageInfo.getList(), InsuranceAccountDetailPO.class);
        return pageInfo;
    }

    public String save(boolean flag, AccountParam param, Long employeeId, String currentUserName) {
        if (flag) {
            InsuranceAccountBatchPO insuranceAccountBatchPO = getInsuranceAccountBatchMapper().getByBillMonth(param.getBillMonth(), param.getPaymentOrganization());
            insuranceAccountBatchPO = encryptUtil.decrypt(insuranceAccountBatchPO, InsuranceAccountBatchPO.class);
            SalaryAssert.isNull(insuranceAccountBatchPO, SalaryI18nUtil.getI18nLabel(100461, "所属月份存在核算数据"));

            InsuranceAccountBatchPO build = InsuranceAccountBatchPO.builder()
                    .paymentOrganization(param.getPaymentOrganization())
                    .accountant(currentUserName)
                    .billMonth(param.getBillMonth())
                    .billStatus(BillStatusEnum.NOT_ARCHIVED.getValue())
                    .remarks(param.getRemarks())
                    .creator(employeeId)
                    .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                    .createTime(new Date())
                    .updateTime(new Date())
                    .deleteType(DeleteTypeEnum.NOT_DELETED.getValue())
                    .paymentOrganization(param.getPaymentOrganization())
                    .socialPay("0")
                    .fundPay("0")
                    .otherPay("0")
                    .build();
            encryptUtil.encrypt(build, InsuranceAccountBatchPO.class);
            getInsuranceAccountBatchMapper().insert(build);
//            LoggerContext insuranceSchemeContext = new LoggerContext();
//            insuranceSchemeContext.setTargetId(String.valueOf(build.getId()));
//            insuranceSchemeContext.setTargetName(build.getBillMonth());
//            insuranceSchemeContext.setOperateType(OperateTypeEnum.ADD.getValue());
//            insuranceSchemeContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(tenantKey, employeeId, 100462, "新增台账"));
//            insuranceSchemeContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(tenantKey, employeeId, 100462, "新增台账"));
//            insuranceSchemeContext.setNewValues(build);
//            siAccountLoggerTemplate.write(insuranceSchemeContext);
        }
        try {
            account(param, employeeId, SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY, currentUserName);
        } catch (Exception e) {
            // 回滚
            List<InsuranceAccountBatchPO> list = Lists.newArrayList(getInsuranceAccountBatchMapper().getByBillMonth(param.getBillMonth(), param.getPaymentOrganization()));
            list = encryptUtil.decryptList(list, InsuranceAccountBatchPO.class);
            if (CollectionUtils.isNotEmpty(list)) {
                list.stream().forEach(f -> {
                    getInsuranceAccountBatchMapper().deleteById(f.getId());
                });
            }
            throw new SalaryRunTimeException(e.getMessage());
        }
        return employeeId.toString();
    }

    public void account(AccountParam param, Long employeeId, String tenantKey, String currentUserName) {

//        Collection<Long> employeeIdsInTaxAgent = getTaxAgentService().listEmployeeIdsInTaxAgent(param.getPaymentOrganization());

        Long paymentOrganization = param.getPaymentOrganization();
//        List<Long>  employeeIds = getInsuranceAccountDetailMapper().selectAccountIds(SalaryDateUtil.getMonthBegin(param.getBillMonth()), paymentOrganization);
        List<Long> employeeIds = getInsuranceAccountDetailMapper().selectEmpByPaymentOrg(paymentOrganization);
//        employeeIds = employeeIds.stream().filter(employeeIdsInTaxAgent::contains).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(employeeIds)) {
            List<InsuranceAccountDetailPO> list = Lists.newArrayList(getInsuranceAccountDetailMapper().queryNormalListByBillMonth(param.getBillMonth(), paymentOrganization));
            encryptUtil.decryptList(list, InsuranceAccountDetailPO.class);
            if (CollectionUtils.isNotEmpty(list)) {
                list.stream().forEach(f -> {
                    getInsuranceAccountDetailMapper().deleteById(f.getId());
                });
            }
        }
        SalaryAssert.notEmpty(employeeIds, "没有需要核算的人员");
        AccountParam selectParam = new AccountParam();
        selectParam.setBillMonth(param.getBillMonth());
        selectParam.setPaymentOrganization(paymentOrganization);
        ExecutorService taskExecutor = Executors.newCachedThreadPool();
        taskExecutor.execute(() -> {
            try {
                DSTenantKeyThreadVar.tenantKey.set(tenantKey);
                accounting(selectParam, employeeId, tenantKey, currentUserName);
            } finally {
                DSTenantKeyThreadVar.tenantKey.remove();
            }
        });
    }

    public void accounting(AccountParam param, Long employeeId, String tenantKey, String currentUserName) {
        //薪资核算进度暂未实现
        ProgressDTO salaryAcctProgressDTO = getSalaryAcctProgressService(user).getProgress(SalaryCacheKey.ACCT_PROGRESS + param.getBillMonth());
        if (salaryAcctProgressDTO != null && salaryAcctProgressDTO.isStatus() && salaryAcctProgressDTO.getProgress().compareTo(BigDecimal.ONE) < 0) {
            return;
        }

        // 初始化进度
        ProgressDTO initProgress = new ProgressDTO()
                .setTitle(SalaryI18nUtil.getI18nLabel(97515, "核算中"))
                .setTitleLabelId(97515L)
                .setTotalQuantity(NumberUtils.INTEGER_ONE)
                .setCalculatedQuantity(NumberUtils.INTEGER_ZERO)
                .setProgress(BigDecimal.ZERO)
                .setStatus(true)
                .setMessage(StringUtils.EMPTY);
        getSalaryAcctProgressService(user).initProgress(SalaryCacheKey.ACCT_PROGRESS + param.getBillMonth(), initProgress);

        log.info("开始核算，当前操作人为:{}", currentUserName);
        doAccounting(param, employeeId, tenantKey, currentUserName);
    }


    public void doAccounting(AccountParam param, Long employeeId, String tenantKey, String currentUserName) {
        log.info("核算时间:{}, 核算月份:{}, 个税扣缴义务人:{}, 是否首次核算:{}", new Date(), param.getBillMonth(), param.getPaymentOrganization(), param.isFlag());
        try {
            List<Long> ids;
            List<Long> validIds = new ArrayList<>();
            if (CollectionUtils.isEmpty(param.getIds())) {
                // 需要分权的情况
//                if(getTaxAgentService().isOpenDevolution()) {
                List<Long> empIds = getInsuranceAccountDetailMapper().selectEmpByPaymentOrg(param.getPaymentOrganization());

                // 获取薪资核算人员规则
                SalarySysConfPO salaryAcctEmployeeRule = getSalarySysConfService(user).getOneByCode(SalarySysConstant.SALARY_ACCT_EMPLOYEE_RULE);
                List<String> status = new ArrayList<>();
                if(Objects.isNull(salaryAcctEmployeeRule) || StringUtils.equals(salaryAcctEmployeeRule.getConfValue(), SalaryAcctEmployeeRuleEnum.BYPAYENDTIME.getValue()) ){
                    // 包含停缴
                    status = Arrays.asList(EmployeeStatusEnum.PAYING.getValue(),EmployeeStatusEnum.STAY_DEL.getValue(),
                            EmployeeStatusEnum.STOP_PAYMENT_FROM_DEL.getValue());
                }else{
                    status = Arrays.asList(EmployeeStatusEnum.PAYING.getValue(),EmployeeStatusEnum.STAY_DEL.getValue());
                }
                List<String> finalStatus = status;
                //过滤出需要核算的人员，即福利档案基础信息表中runStatus为正在缴纳和待减员的人员
                List<InsuranceArchivesBaseInfoPO> baseInfoPOList = getInsuranceBaseInfoMapper().listAll();
                List<Long> canAccountIds = baseInfoPOList.stream()
                        .filter(f->f.getPaymentOrganization().equals(param.getPaymentOrganization())
                                && (finalStatus.contains(f.getRunStatus()) ))
                        .map(InsuranceArchivesBaseInfoPO::getEmployeeId)
                        .collect(Collectors.toList());

                //20231122逻辑优化，过滤出不在起始缴纳月和最后缴纳月区间的人员
                List<Long> empIdsInPayMonthRange = listCanPayEmpIds(param.getPaymentOrganization(), param.getBillMonth());
                empIds = empIds.stream().filter(f->canAccountIds.contains(f) && empIdsInPayMonthRange.contains(f)).collect(Collectors.toList());

                //过滤不在扣缴义务人下的数据
//                Collection<Long> employeeIdsInTaxAgent = getTaxAgentService().listEmployeeIdsInTaxAgent(param.getPaymentOrganization());
//                empIds = empIds.stream().filter(employeeIdsInTaxAgent::contains).collect(Collectors.toList());

                List<InsuranceArchivesSocialSchemePO> socials = siArchivesBiz.getSocialByEmployeeIds(empIds);
                //过滤出目标个税扣缴义务人相关信息
                socials = socials.stream().filter(f -> f.getPaymentOrganization().equals(param.getPaymentOrganization())).collect(Collectors.toList());
                List<Long> emp1 = socials.stream()
                        .filter(s -> !(StringUtils.isBlank(s.getSocialEndTime()) && StringUtils.isBlank(s.getSocialStartTime())) &&
                                (StringUtils.isBlank(s.getSocialEndTime()) || (SalaryDateUtil.stringToDate(s.getSocialEndTime() + "-01") != null && !SalaryDateUtil.stringToDate(param.getBillMonth() + "-01").after(SalaryDateUtil.stringToDate(s.getSocialEndTime() + "-01")))) )
                        .map(InsuranceArchivesSocialSchemePO::getEmployeeId)
                        .collect(Collectors.toList());

                List<InsuranceArchivesFundSchemePO> funds = siArchivesBiz.getFundByEmployeeIds(empIds);
                //过滤出目标个税扣缴义务人相关信息
                funds = funds.stream().filter(f -> f.getPaymentOrganization().equals(param.getPaymentOrganization())).collect(Collectors.toList());
                List<Long> emp2 = funds.stream()
                        .filter(s -> !(StringUtils.isBlank(s.getFundStartTime()) && StringUtils.isBlank(s.getFundEndTime())) &&
                                (StringUtils.isBlank(s.getFundEndTime()) || (SalaryDateUtil.stringToDate(s.getFundEndTime() + "-01") != null && !SalaryDateUtil.stringToDate(param.getBillMonth() + "-01").after(SalaryDateUtil.stringToDate(s.getFundEndTime() + "-01")))))
                        .map(InsuranceArchivesFundSchemePO::getEmployeeId)
                        .collect(Collectors.toList());

                List<InsuranceArchivesOtherSchemePO> others = siArchivesBiz.getOtherByEmployeeIds(empIds);
                //过滤出目标个税扣缴义务人相关信息
                others = others.stream().filter(f -> f.getPaymentOrganization().equals(param.getPaymentOrganization())).collect(Collectors.toList());
                List<Long> emp3 = others.stream()
                        .filter(s -> !(StringUtils.isBlank(s.getOtherStartTime()) && StringUtils.isBlank(s.getOtherEndTime())) &&
                                (StringUtils.isBlank(s.getOtherEndTime()) || (SalaryDateUtil.stringToDate(s.getOtherEndTime() + "-01") != null && !SalaryDateUtil.stringToDate(param.getBillMonth() + "-01").after(SalaryDateUtil.stringToDate(s.getOtherEndTime() + "-01")))))
                        .map(InsuranceArchivesOtherSchemePO::getEmployeeId)
                        .collect(Collectors.toList());
                validIds.addAll(emp1);
                validIds.addAll(emp2);
                validIds.addAll(emp3);

                List<Long> finalValidIds = validIds.stream().distinct().collect(Collectors.toList());
                ids = empIds.stream().filter(finalValidIds::contains).collect(Collectors.toList());

//                } else {
//                    ids = getInsuranceAccountDetailMapper().selectAccountIds(SalaryDateUtil.getMonthBegin(param.getBillMonth()), null);
//                }
            } else {
                ids = param.getIds();
            }
            if (CollectionUtils.isEmpty(ids)) {
                getSalaryAcctProgressService(user).finish(SalaryCacheKey.ACCT_PROGRESS + param.getBillMonth(), true);
//                getSalaryAcctProgressService(user).fail(SalaryCacheKey.ACCT_PROGRESS + param.getBillMonth(), SalaryI18nUtil.getI18nLabel( 100468, "无需要核算的人员"));
                return;
            }
//            SalaryAcctProgressDTO salaryAcctProgressDTO = new SalaryAcctProgressDTO(SalaryI18nUtil.getI18nLabel(97515, "核算中"), 97515L, ids.size(), 0,
//                    BigDecimal.ZERO, true, "", true);
            //salaryAcctProgressService.initProgress(tenantKey + param.getBillMonth(), salaryAcctProgressDTO, employeeId, tenantKey);

            // 初始化进度
            ProgressDTO initProgress = new ProgressDTO()
                    .setTitle(SalaryI18nUtil.getI18nLabel(97515, "核算中"))
                    .setTitleLabelId(97515L)
                    .setTotalQuantity(ids.size())
                    .setCalculatedQuantity(NumberUtils.INTEGER_ZERO)
                    .setProgress(BigDecimal.ZERO)
                    .setStatus(true)
                    .setMessage(StringUtils.EMPTY);
            getSalaryAcctProgressService(user).initProgress(SalaryCacheKey.ACCT_PROGRESS + param.getBillMonth(), initProgress);
           /* List<List<Long>> partition = Lists.partition(ids, 100);
            CountDownLatch countDownLatch = new CountDownLatch(partition.size());
            BlockingDeque<Boolean> results = new LinkedBlockingDeque<>(partition.size());*/
            log.info("开始生成福利核算数据，待处理人员数量:{}", ids.size());
            commonAccount(/*countDownLatch, results, */param.getBillMonth(), ids, employeeId, tenantKey, param.getPaymentOrganization());
            log.info("福利核算数据生成完毕，开始数据处理");
          /*  for (List<Long> batchIds : partition) {
                taskExecutor.execute(() -> {
                    commonAccount(countDownLatch, results, param.getBillMonth(), batchIds, simpleEmployee);
                });
            }
            countDownLatch.await();
            boolean allSuccess = results.stream().allMatch(Boolean::booleanValue);*/
            /* if (allSuccess) {*/
            handleData(ids, param, employeeId, tenantKey, currentUserName);
            log.info("福利核算数据处理完毕！");
            /*}*/
            List<List<Long>> partition = Lists.partition((List<Long>) ids, 100);
            partition.forEach(part -> {
                getSIAccountDetailTempMapper().batchDelByEmpIdsAndMonthAndPayOrg(part, param.getBillMonth(), param.getPaymentOrganization());
            });
            log.info("更新福利核算进度······");
            getSalaryAcctProgressService(user).finish(SalaryCacheKey.ACCT_PROGRESS + param.getBillMonth(), true);
            log.info("福利核算进度完成！");
        } catch (Exception e) {
            log.error("account run fail", e);
            getSalaryAcctProgressService(user).fail(SalaryCacheKey.ACCT_PROGRESS + param.getBillMonth(), SalaryI18nUtil.getI18nLabel(99642, "福利核算出错") + ": " + e.getMessage());

            List<InsuranceAccountBatchPO> list = Lists.newArrayList(getInsuranceAccountBatchMapper().getByBillMonth(param.getBillMonth(), param.getPaymentOrganization()));
            if (CollectionUtils.isNotEmpty(list)) {
                list.stream().forEach(f -> {
                    getInsuranceAccountBatchMapper().deleteById(f.getId());
                });
            }

            //薪资核算进度暂未实现
            //salaryAcctProgressService.del(tenantKey + param.getBillMonth(), employeeId, tenantKey);
            //logger.error("welfare account error:{}", e.getMessage(), e);
        }
    }

    /**
     * 根据个税扣缴义务人和账单月，获取三类福利档案中符合缴纳开始结束月区间的人员id
     * @param paymentOrganization
     * @param billMonth
     * @return
     */
    public List<Long> listCanPayEmpIds(Long paymentOrganization, String billMonth) {
        List<Long> listCanPayEmpIds = new ArrayList<>();
        //社保档案中可进行缴纳的人员
        List<Long> socialCanPayEmpIds = getSocialSchemeMapper().listCanPayEmpIds(paymentOrganization, billMonth, 0);
        //公积金档案中可进行缴纳的人员
        List<Long> fundCanPayEmpIds = getFundSchemeMapper().listCanPayEmpIds(paymentOrganization, billMonth, 0);
        //其他福利档案中可进行缴纳的人员
        List<Long> otherCanPayEmpIds = getOtherSchemeMapper().listCanPayEmpIds(paymentOrganization, billMonth, 0);
        if (socialCanPayEmpIds != null && socialCanPayEmpIds.size() > 0) {
            listCanPayEmpIds.addAll(socialCanPayEmpIds);
        }
        if (fundCanPayEmpIds != null && fundCanPayEmpIds.size() > 0) {
            listCanPayEmpIds.addAll(fundCanPayEmpIds);
        }
        if (otherCanPayEmpIds != null && otherCanPayEmpIds.size() > 0) {
            listCanPayEmpIds.addAll(otherCanPayEmpIds);
        }
        //去重
        listCanPayEmpIds = listCanPayEmpIds.stream().distinct().collect(Collectors.toList());
        return listCanPayEmpIds;
    }

    public void commonAccount(/*CountDownLatch countDownLatch, BlockingDeque<Boolean> results,*/ String billMonth, List<Long> ids, Long employeeId, String tenantKey, Long paymentOrganization) {
        /* try {*/
        SIArchivesBiz siArchivesBiz = new SIArchivesBiz();
        Map<Long, InsuranceArchivesAccountPO> insuranceArchivesAccountPOS = siArchivesBiz.buildBatchAccount(ids, paymentOrganization);
        List<InsuranceAccountDetailTempPO> list = new ArrayList<>();
        int count = 0;
        for (Map.Entry<Long, InsuranceArchivesAccountPO> entry : insuranceArchivesAccountPOS.entrySet()) {
            Long k = entry.getKey();
            InsuranceArchivesAccountPO v = entry.getValue();
            InsuranceAccountDetailPO insuranceAccountDetailPO = new InsuranceAccountDetailPO();
            insuranceAccountDetailPO.setBillMonth(billMonth);
            insuranceAccountDetailPO.setBillStatus(BillStatusEnum.NOT_ARCHIVED.getValue());
            insuranceAccountDetailPO.setCreator(employeeId);
            insuranceAccountDetailPO.setCreateTime(new Date());
            insuranceAccountDetailPO.setDeleteType(DeleteTypeEnum.NOT_DELETED.getValue());
            insuranceAccountDetailPO.setEmployeeId(k);
            insuranceAccountDetailPO.setUpdateTime(new Date());
            insuranceAccountDetailPO.setPaymentStatus(PaymentStatusEnum.COMMON.getValue());
            insuranceAccountDetailPO.setResourceFrom(ResourceFromEnum.SYSTEM.getValue());
            insuranceAccountDetailPO.setTenantKey(tenantKey);
            insuranceAccountDetailPO.setPaymentOrganization(paymentOrganization);

            //核算社保
            accountSocial(insuranceAccountDetailPO, v, billMonth, tenantKey);
            //核算公积金
            accountFund(insuranceAccountDetailPO, v, billMonth, tenantKey);
            //核算其他福利
            accountOther(insuranceAccountDetailPO, v, billMonth, tenantKey);
            //计算合计
            account(insuranceAccountDetailPO);
            //临时表PO
            InsuranceAccountDetailTempPO insuranceAccountDetailTempPO = new InsuranceAccountDetailTempPO();
            BeanUtils.copyProperties(insuranceAccountDetailPO, insuranceAccountDetailTempPO);
            list.add(insuranceAccountDetailTempPO);
            count++;

            if (count % 50 == 0 || count >= ids.size()) {
                //salaryAcctProgressService.getAndAddCalculatedQty(tenantKey + billMonth, count >= ids.size() ? count % 50 : 50);

                if (count >= ids.size()) {
                    getSalaryAcctProgressService(user).updateProgress(SalaryCacheKey.ACCT_PROGRESS + billMonth, BigDecimal.valueOf(0.99), false);
                    log.info("更新福利核算进度，当前进度为:{}", getSalaryAcctProgressService(user).getProgress(SalaryCacheKey.ACCT_PROGRESS + billMonth));
                } else {
                    getSalaryAcctProgressService(user).getAndAddCalculatedQty(SalaryCacheKey.ACCT_PROGRESS + billMonth, count >= ids.size() ? count % 50 : 50);
                    log.info("更新福利核算进度，当前进度为:{}", getSalaryAcctProgressService(user).getProgress(SalaryCacheKey.ACCT_PROGRESS + billMonth));
                }

            }

        }

        //临时表入库前先对（可能存在的）历史数据进行删除
        List<List<Long>> partition = Lists.partition((List<Long>) ids, 100);
        partition.forEach(part -> {
            getSIAccountDetailTempMapper().batchDelByEmpIdsAndMonthAndPayOrg(part, billMonth, paymentOrganization);
        });
        //临时表数据入库
        if (CollectionUtils.isNotEmpty(list)) {
            encryptUtil.encryptList(list, InsuranceAccountDetailTempPO.class);
            List<List<InsuranceAccountDetailTempPO>> lists = splitList(list, 20);
            lists.forEach(subList -> {
                getSIAccountDetailTempMapper().batchSaveAccountTempDetails(subList);
            });
        }

       /* } catch (Exception e) {
            logger.error("福利核算失败：{}", e.getMessage(), e);
            results.add(false);
        } finally {
            countDownLatch.countDown();
        }*/
    }

    private List<List<InsuranceAccountDetailTempPO>> splitList(List<InsuranceAccountDetailTempPO> list, int groupSize) {
        int length = list.size();
        // 计算可以分成多少组
        int num = (length + groupSize - 1) / groupSize;
        List<List<InsuranceAccountDetailTempPO>> newList = new ArrayList<>(num);
        for (int i = 0; i < num; i++) {
            // 开始位置
            int fromIndex = i * groupSize;
            // 结束位置
            int toIndex = (i + 1) * groupSize < length ? (i + 1) * groupSize : length;
            newList.add(list.subList(fromIndex, toIndex));
        }
        return newList;
    }


    private void handleData(List<Long> ids, AccountParam param, Long employeeId, String tenantKey, String currentUserName) {
        //事务后续处理
        //TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
        String billMonth = param.getBillMonth();
        try {
//            List<InsuranceAccountDetailTempPO> list = getSIAccountDetailTempMapper().getListByEmployeeIdsAndBillMonth(ids, billMonth, param.getPaymentOrganization());
            List<InsuranceAccountDetailTempPO> list = new ArrayList<>();
            List<List<Long>> partitionDetailTempInfo = Lists.partition((List<Long>) ids, 100);
            partitionDetailTempInfo.forEach(part -> list.addAll(
                    getSIAccountDetailTempMapper().getListByEmployeeIdsAndBillMonth(part, billMonth, param.getPaymentOrganization())));

            encryptUtil.decryptList(list, InsuranceAccountDetailTempPO.class);
            Integer paymentStatus = 0;
            log.info("核算明细临时表 hrsa_bill_detail_temp待处理数量：{}", list.size());
            List<List<Long>> partitionIds = Lists.partition((List<Long>) ids, 100);
            log.info("bill_detail入库前删除数据数量：{}", ids.size());
            for (List<Long> part : partitionIds) {
                getInsuranceAccountDetailMapper().batchDelAccountDetails(part, billMonth, param.getPaymentOrganization(), paymentStatus);

                //删除账单月份+个税扣缴义务人+人员id下的调差数据
                getInsuranceCompensationMapper().deleteByBillMonthPayOrgEmpIds(InsuranceCompensationPO.builder()
                        .billMonth(billMonth)
                        .paymentOrganization(param.getPaymentOrganization())
                        .employeeIds(part)
                        .build());
            }

            //生成bill_detail入库数据
            List<InsuranceAccountDetailPO> collect = list.stream().map(item -> {
                InsuranceAccountDetailPO insuranceAccountDetailPO = new InsuranceAccountDetailPO();
                BeanUtils.copyProperties(item, insuranceAccountDetailPO);
                return insuranceAccountDetailPO;
            }).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(collect)) {
                log.info("bill_detail入库数据数量：{}", collect.size());
                batchSaveAccountInspectDetail(collect, billMonth, tenantKey);
                encryptUtil.encryptList(collect, InsuranceAccountDetailPO.class);
                List<List<InsuranceAccountDetailPO>> lists = splitDetailList(collect, 20);
                lists.forEach(subList -> {
                    getInsuranceAccountDetailMapper().batchSaveAccountDetails(subList);
                });
                updateBatchAccount(param, employeeId, tenantKey, currentUserName);
            }
            //transactionManager.commit(status);
        } catch (Exception e) {
            log.error("福利核算数据处理失败", e);
            getSalaryAcctProgressService(user).fail(SalaryCacheKey.ACCT_PROGRESS + param.getBillMonth(), SalaryI18nUtil.getI18nLabel(99642, "福利核算出错") + ": " + e.getMessage());
            //transactionManager.rollback(status);
            throw e;
        }
    }


    public InsuranceAccountDetailPO account(InsuranceAccountDetailPO insuranceAccountDetailPO) {
        //个人合计
        BigDecimal socialPerson =
                StringUtils.isBlank(insuranceAccountDetailPO.getSocialPerSum()) ? new BigDecimal("0") : new BigDecimal(insuranceAccountDetailPO.getSocialPerSum());
        BigDecimal fundPerson =
                StringUtils.isBlank(insuranceAccountDetailPO.getFundPerSum()) ? new BigDecimal("0") : new BigDecimal(insuranceAccountDetailPO.getFundPerSum());
        BigDecimal otherPerson =
                StringUtils.isBlank(insuranceAccountDetailPO.getOtherPerSum()) ? new BigDecimal("0") : new BigDecimal(insuranceAccountDetailPO.getOtherPerSum());
        BigDecimal perSum = socialPerson.add(fundPerson).add(otherPerson);
        insuranceAccountDetailPO.setPerSum(perSum.toPlainString());
        //单位合计
        BigDecimal socialCom =
                StringUtils.isBlank(insuranceAccountDetailPO.getSocialComSum()) ? new BigDecimal("0") : new BigDecimal(insuranceAccountDetailPO.getSocialComSum());
        BigDecimal fundCom = StringUtils.isBlank(insuranceAccountDetailPO.getFundComSum()) ? new BigDecimal("0") : new BigDecimal(insuranceAccountDetailPO.getFundComSum());
        BigDecimal otherCom =
                StringUtils.isBlank(insuranceAccountDetailPO.getOtherComSum()) ? new BigDecimal("0") : new BigDecimal(insuranceAccountDetailPO.getOtherComSum());
        BigDecimal comSum = socialCom.add(fundCom).add(otherCom);
        insuranceAccountDetailPO.setComSum(comSum.toPlainString());
        //社保合计
        insuranceAccountDetailPO.setSocialSum(socialPerson.add(socialCom).toPlainString());
        //公积金合计
        insuranceAccountDetailPO.setFundSum(fundPerson.add(fundCom).toPlainString());
        //其他福利合计
        insuranceAccountDetailPO.setOtherSum(otherPerson.add(otherCom).toPlainString());
        //合计
        insuranceAccountDetailPO.setTotal(perSum.add(comSum).toPlainString());
        return insuranceAccountDetailPO;
    }

    public InsuranceAccountDetailPO accountOther(InsuranceAccountDetailPO insuranceAccountDetailPO, InsuranceArchivesAccountPO accountPO, String billMonth, String tenantKey) {
        boolean welBaseDiffSign = siArchivesBiz.isDiffWelBase();
        if (accountPO.getOther() != null) {
            InsuranceArchivesOtherSchemePO otherPO = accountPO.getOther();
            insuranceAccountDetailPO.setOtherPayOrg(otherPO.getPaymentOrganization());
            insuranceAccountDetailPO.setOtherSchemeId(otherPO.getOtherSchemeId());
            insuranceAccountDetailPO.setOtherPaymentBaseString(otherPO.getOtherPaymentBaseString());
            insuranceAccountDetailPO.setOtherPaymentComBaseString(otherPO.getOtherPaymentComBaseString());
            //判断是否在起始缴纳月和最后缴纳月之间
            Boolean inDataRange = SalaryDateUtil.monthInRange(insuranceAccountDetailPO.getBillMonth(), otherPO.getOtherStartTime(), otherPO.getOtherEndTime());
            if ((Objects.equals(NonPaymentEnum.YES.getValue(), otherPO.getNonPayment()) || otherPO.getNonPayment() == null) && otherPO.getOtherSchemeId() != null && inDataRange) {
                List<InsuranceSchemeDetailPO> detailPOS = getInsuranceSchemeDetailMapper().queryListBySchemeId(otherPO.getOtherSchemeId());
                encryptUtil.decryptList(detailPOS, InsuranceSchemeDetailPO.class);
                //方案中包含的需要缴纳其他的个人福利
                int monthIndex = Integer.parseInt(billMonth.split("-")[1]) - 1;
                Map<Long, InsuranceSchemeDetailPO> otherPerson = detailPOS.stream()
                        .filter(item -> Objects.equals(IsPaymentEnum.YES.getValue(), item.getIsPayment()) && Objects.equals(item.getPaymentScope(), PaymentScopeEnum.SCOPE_PERSON.getValue())
                                && (item.getPaymentCycle() == null || item.getPaymentCycle() == 0 || (item.getPaymentCycle() == 1 && String.valueOf(item.getCycleSetting().charAt(monthIndex)).equals("1"))))
                        .collect(
                                Collectors.toMap(InsuranceSchemeDetailPO::getInsuranceId, Function.identity()));
                //档案中包含的基数信息
                HashMap<String, String> archivesPerson = JSON.parseObject(otherPO.getOtherPaymentBaseString(), new HashMap<String, String>().getClass());
                //需要核算其他的福利id  个人
                List<Long> needArchivesPerson = new ArrayList<>();
                if (archivesPerson != null) {
                    archivesPerson.forEach((id, value) -> {
                        if (otherPerson.containsKey(Long.valueOf(id))) {
                            needArchivesPerson.add(Long.valueOf(id));
                        }
                    });
                }
                //避免福利档案的方案未设置基数，导致核算时遗漏这些福利项的核算，遍历下方案相关福利项，并将遗漏的福利项id添加
                if(otherPerson.size() > 0) {
                    otherPerson.forEach((id, object) -> {
                        if (!needArchivesPerson.contains(id)) {
                            needArchivesPerson.add(id);
                        }
                    });
                }
                //判断核算周期、核算月、福利起始缴纳月的关系
                checkCycleSettingWithStartMonth(otherPerson, billMonth, otherPO.getOtherStartTime());

                List<BigDecimal> otherPer = new ArrayList<>();
                Map<String, String> otherPerJsonMap = new HashMap<>();
                needArchivesPerson.stream().forEach(e -> {
                    InsuranceSchemeDetailPO po = otherPerson.get(e);
                    BigDecimal paymentProportion = new BigDecimal(StringUtils.isBlank(po.getPaymentProportion()) ? "0" : po.getPaymentProportion()).divide(new BigDecimal("100"));
                    BigDecimal paymentNum = new BigDecimal((ObjectUtil.isEmpty(archivesPerson) || StringUtils.isBlank(archivesPerson.get(String.valueOf(e)))) ? "0" : archivesPerson.get(String.valueOf(e)));
                    BigDecimal fixedCost = StringUtils.isBlank(po.getFixedCost()) ? new BigDecimal("0") : new BigDecimal(po.getFixedCost());
                    Integer newScale = po.getValidNum() == null ? 2 : po.getValidNum();
//                    BigDecimal result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    BigDecimal result = new BigDecimal("0");
                    if (po.getPaymentCycle() != null && po.getPaymentCycle() == 1) {
                        int monthValue = 1;
                        for (int i = monthIndex - 1; i >= 0; i--) {
                            String cycleValue = po.getCycleSetting().charAt(i) + "";
                            if (Integer.parseInt(cycleValue) == 1) {
                                break;
                            }
                            monthValue++;
                        }
                        if (po.getAccountType() == 1) {
                            paymentNum = paymentNum.multiply(new BigDecimal(monthValue));
                            fixedCost = fixedCost.multiply(new BigDecimal(monthValue));
                            result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                        } else {
                            for (int i = 0; i < monthValue; i++) {
                                result = result.add(SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost)));
                            }
                        }
                    } else {
                        result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    }
                    otherPerJsonMap.put(String.valueOf(e), result.toPlainString());
                    otherPer.add(result);
                });
                insuranceAccountDetailPO.setOtherPerJson(JSON.toJSONString(otherPerJsonMap));
                BigDecimal otherPerSum = new BigDecimal("0");
                for (BigDecimal bigDecimal : otherPer) {
                    otherPerSum = otherPerSum.add(bigDecimal);
                }
                insuranceAccountDetailPO.setOtherPerSum(otherPerSum.toPlainString());

                //方案中包含的需要缴纳公积金的单位福利
                Map<Long, InsuranceSchemeDetailPO> otherCom = detailPOS.stream()
                        .filter(
                                item -> Objects.equals(IsPaymentEnum.YES.getValue(), item.getIsPayment()) && Objects.equals(item.getPaymentScope(), PaymentScopeEnum.SCOPE_COMPANY.getValue())
                                        && (item.getPaymentCycle() == null || item.getPaymentCycle() == 0 || (item.getPaymentCycle() == 1 && String.valueOf(item.getCycleSetting().charAt(monthIndex)).equals("1"))))
                        .collect(
                                Collectors.toMap(InsuranceSchemeDetailPO::getInsuranceId, Function.identity()));
                //档案中包含的基数信息
//                HashMap<String, String> archivesCom = JSON.parseObject(otherPO.getOtherPaymentBaseString(), new HashMap<String, String>().getClass());
                HashMap<String, String> archivesCom = new HashMap<>();
                if (welBaseDiffSign) {
                    archivesCom = JSON.parseObject(otherPO.getOtherPaymentComBaseString(), new HashMap<String, String>().getClass());
                } else {
                    archivesCom = JSON.parseObject(otherPO.getOtherPaymentBaseString(), new HashMap<String, String>().getClass());
                }
                //需要核算其他的福利id  单位
                List<Long> needArchivesCom = new ArrayList<>();
                if (archivesCom != null) {
                    archivesCom.forEach((id, value) -> {
                        if (otherCom.containsKey(Long.valueOf(id))) {
                            needArchivesCom.add(Long.valueOf(id));
                        }
                    });
                }
                //避免福利档案的方案未设置基数，导致核算时遗漏这些福利项的核算，遍历下方案相关福利项，并将遗漏的福利项id添加
                if(otherCom.size() > 0) {
                    otherCom.forEach((id, object) -> {
                        if (!needArchivesCom.contains(id)) {
                            needArchivesCom.add(id);
                        }
                    });
                }
                //判断核算周期、核算月、福利起始缴纳月的关系
                checkCycleSettingWithStartMonth(otherCom, billMonth, otherPO.getOtherStartTime());

                List<BigDecimal> otherComList = new ArrayList<>();
                Map<String, String> otherComJsonMap = new HashMap<>();
                HashMap<String, String> finalArchivesCom = archivesCom;
                needArchivesCom.stream().forEach(e -> {
                    InsuranceSchemeDetailPO po = otherCom.get(e);
                    BigDecimal paymentProportion = new BigDecimal(StringUtils.isBlank(po.getPaymentProportion()) ? "0" : po.getPaymentProportion()).divide(new BigDecimal("100"));
                    BigDecimal paymentNum = new BigDecimal((ObjectUtil.isEmpty(finalArchivesCom) || StringUtils.isBlank(finalArchivesCom.get(String.valueOf(e)))) ? "0" : finalArchivesCom.get(String.valueOf(e)));
                    BigDecimal fixedCost = StringUtils.isBlank(po.getFixedCost()) ? new BigDecimal("0") : new BigDecimal(po.getFixedCost());
                    Integer newScale = po.getValidNum() == null ? 2 : po.getValidNum();
//                    BigDecimal result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    BigDecimal result = new BigDecimal("0");
                    if (Objects.equals(po.getPaymentCycle(), 1)) {
                        int monthValue = 1;
                        for (int i = monthIndex - 1; i >= 0; i--) {
                            String cycleValue = po.getCycleSetting().charAt(i) + "";
                            if (Integer.parseInt(cycleValue) == 1) {
                                break;
                            }
                            monthValue++;
                        }
                        if (po.getAccountType() == 1) {
                            paymentNum = paymentNum.multiply(new BigDecimal(monthValue));
                            fixedCost = fixedCost.multiply(new BigDecimal(monthValue));
                            result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                        } else {
                            for (int i = 0; i < monthValue; i++) {
                                result = result.add(SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost)));
                            }
                        }
                    } else {
                        result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    }
                    otherComJsonMap.put(String.valueOf(e), result.toPlainString());
                    otherComList.add(result);
                });
                insuranceAccountDetailPO.setOtherComJson(JSON.toJSONString(otherComJsonMap));
                BigDecimal otherComSum = new BigDecimal("0");
                for (BigDecimal bigDecimal : otherComList) {
                    otherComSum = otherComSum.add(bigDecimal);
                }
                insuranceAccountDetailPO.setOtherComSum(otherComSum.toPlainString());
            }
        }
        return insuranceAccountDetailPO;
    }


    public InsuranceAccountDetailPO accountFund(InsuranceAccountDetailPO insuranceAccountDetailPO, InsuranceArchivesAccountPO accountPO, String billMonth, String tenantKey) {
        boolean welBaseDiffSign = siArchivesBiz.isDiffWelBase();
        if (accountPO.getFund() != null) {
            InsuranceArchivesFundSchemePO fundPO = accountPO.getFund();
            insuranceAccountDetailPO.setFundPayOrg(fundPO.getPaymentOrganization());
            insuranceAccountDetailPO.setFundAccount(fundPO.getFundAccount());
            insuranceAccountDetailPO.setSupplementFundAccount(fundPO.getSupplementFundAccount());
            insuranceAccountDetailPO.setFundSchemeId(fundPO.getFundSchemeId());
            insuranceAccountDetailPO.setFundPaymentBaseString(fundPO.getFundPaymentBaseString());
            insuranceAccountDetailPO.setFundPaymentComBaseString(fundPO.getFundPaymentComBaseString());
            //判断是否在起始缴纳月和最后缴纳月之间
            Boolean inDataRange = SalaryDateUtil.monthInRange(insuranceAccountDetailPO.getBillMonth(), fundPO.getFundStartTime(), fundPO.getFundEndTime());
            if ((NonPaymentEnum.YES.getValue() == fundPO.getNonPayment() || fundPO.getNonPayment() == null) && fundPO.getFundSchemeId() != null && inDataRange) {
                List<InsuranceSchemeDetailPO> detailPOS = getInsuranceSchemeDetailMapper().queryListBySchemeId(fundPO.getFundSchemeId());
                encryptUtil.decryptList(detailPOS, InsuranceSchemeDetailPO.class);
                //方案中包含的需要缴纳社保的个人福利
                int monthIndex = Integer.parseInt(billMonth.split("-")[1]) - 1;
                Map<Long, InsuranceSchemeDetailPO> fundperson = detailPOS.stream()
                        .filter(item -> Objects.equals(IsPaymentEnum.YES.getValue(), item.getIsPayment()) && Objects.equals(item.getPaymentScope(), PaymentScopeEnum.SCOPE_PERSON.getValue())
                                && (item.getPaymentCycle() == null || item.getPaymentCycle() == 0 || (item.getPaymentCycle() == 1 && String.valueOf(item.getCycleSetting().charAt(monthIndex)).equals("1"))))
                        .collect(
                                Collectors.toMap(InsuranceSchemeDetailPO::getInsuranceId, Function.identity()));
                //档案中包含的基数信息
                HashMap<String, String> archivesPerson = JSON.parseObject(fundPO.getFundPaymentBaseString(), new HashMap<String, String>().getClass());
                //需要核算公积金的福利id  个人
                List<Long> needArchivesPerson = new ArrayList<>();
                if (archivesPerson != null) {
                    archivesPerson.forEach((id, value) -> {
                        if (fundperson.containsKey(Long.valueOf(id))) {
                            needArchivesPerson.add(Long.valueOf(id));
                        }
                    });
                }
                //避免福利档案的方案未设置基数，导致核算时遗漏这些福利项的核算，遍历下方案相关福利项，并将遗漏的福利项id添加
                if(fundperson.size() > 0) {
                    fundperson.forEach((id, object) -> {
                        if (!needArchivesPerson.contains(id)) {
                            needArchivesPerson.add(id);
                        }
                    });
                }
                //判断核算周期、核算月、福利起始缴纳月的关系
                checkCycleSettingWithStartMonth(fundperson, billMonth, fundPO.getFundStartTime());

                List<BigDecimal> fundPer = new ArrayList<>();
                Map<String, String> fundPerJsonMap = new HashMap<>();
                needArchivesPerson.stream().forEach(e -> {
                    InsuranceSchemeDetailPO po = fundperson.get(e);
                    BigDecimal paymentProportion = new BigDecimal(StringUtils.isBlank(po.getPaymentProportion()) ? "0" : po.getPaymentProportion()).divide(new BigDecimal("100"));
                    BigDecimal paymentNum = new BigDecimal((ObjectUtil.isEmpty(archivesPerson) || StringUtils.isBlank(archivesPerson.get(String.valueOf(e)))) ? "0" : archivesPerson.get(String.valueOf(e)));
                    BigDecimal fixedCost = StringUtils.isBlank(po.getFixedCost()) ? new BigDecimal("0") : new BigDecimal(po.getFixedCost());
                    Integer newScale = po.getValidNum() == null ? 2 : po.getValidNum();
//                    BigDecimal result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    BigDecimal result = new BigDecimal("0");
                    if (Objects.equals(po.getPaymentCycle(), 1)) {
                        int monthValue = 1;
                        for (int i = monthIndex - 1; i >= 0; i--) {
                            String cycleValue = po.getCycleSetting().charAt(i) + "";
                            if (Integer.parseInt(cycleValue) == 1) {
                                break;
                            }
                            monthValue++;
                        }
                        if (po.getAccountType() == 1) {
                            paymentNum = paymentNum.multiply(new BigDecimal(monthValue));
                            fixedCost = fixedCost.multiply(new BigDecimal(monthValue));
                            result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                        } else {
                            for (int i = 0; i < monthValue; i++) {
                                result = result.add(SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost)));
                            }
                        }
                    } else {
                        result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    }
                    fundPerJsonMap.put(String.valueOf(e), result.toPlainString());
                    fundPer.add(result);
                });
                insuranceAccountDetailPO.setFundPerJson(JSON.toJSONString(fundPerJsonMap));
                BigDecimal funPerSum = new BigDecimal("0");
                for (BigDecimal bigDecimal : fundPer) {
                    funPerSum = funPerSum.add(bigDecimal);
                }
                insuranceAccountDetailPO.setFundPerSum(funPerSum.toPlainString());

                //方案中包含的需要缴纳公积金的单位福利
                Map<Long, InsuranceSchemeDetailPO> fundCom = detailPOS.stream()
                        .filter(item -> Objects.equals(IsPaymentEnum.YES.getValue(), item.getIsPayment()) && Objects.equals(item.getPaymentScope(), PaymentScopeEnum.SCOPE_COMPANY.getValue())
                                && (item.getPaymentCycle() == null || item.getPaymentCycle() == 0 || (item.getPaymentCycle() == 1 && String.valueOf(item.getCycleSetting().charAt(monthIndex)).equals("1"))))
                        .collect(
                                Collectors.toMap(InsuranceSchemeDetailPO::getInsuranceId, Function.identity()));
                //档案中包含的基数信息
//                HashMap<String, String> archivesCom = JSON.parseObject(fundPO.getFundPaymentBaseString(), new HashMap<String, String>().getClass());
                HashMap<String, String> archivesCom = new HashMap<>();
                if (welBaseDiffSign) {
                    archivesCom = JSON.parseObject(fundPO.getFundPaymentComBaseString(), new HashMap<String, String>().getClass());
                } else {
                    archivesCom = JSON.parseObject(fundPO.getFundPaymentBaseString(), new HashMap<String, String>().getClass());
                }
                //需要核算公积金的福利id  单位
                List<Long> needArchivesCom = new ArrayList<>();
                if (archivesCom != null) {
                    archivesCom.forEach((id, value) -> {
                        if (fundCom.containsKey(Long.valueOf(id))) {
                            needArchivesCom.add(Long.valueOf(id));
                        }
                    });
                }
                //避免福利档案的方案未设置基数，导致核算时遗漏这些福利项的核算，遍历下方案相关福利项，并将遗漏的福利项id添加
                if(fundCom.size() > 0) {
                    fundCom.forEach((id, object) -> {
                        if (!needArchivesCom.contains(id)) {
                            needArchivesCom.add(id);
                        }
                    });
                }
                //判断核算周期、核算月、福利起始缴纳月的关系
                checkCycleSettingWithStartMonth(fundCom, billMonth, fundPO.getFundStartTime());

                List<BigDecimal> fundComList = new ArrayList<>();
                Map<String, String> fundComJsonMap = new HashMap<>();
                HashMap<String, String> finalArchivesCom = archivesCom;
                needArchivesCom.stream().forEach(e -> {
                    InsuranceSchemeDetailPO po = fundCom.get(e);
                    BigDecimal paymentProportion = new BigDecimal(StringUtils.isBlank(po.getPaymentProportion()) ? "0" : po.getPaymentProportion()).divide(new BigDecimal("100"));
                    BigDecimal paymentNum = new BigDecimal((ObjectUtil.isEmpty(finalArchivesCom) || StringUtils.isBlank(finalArchivesCom.get(String.valueOf(e)))) ? "0" : finalArchivesCom.get(String.valueOf(e)));
                    BigDecimal fixedCost = StringUtils.isBlank(po.getFixedCost()) ? new BigDecimal("0") : new BigDecimal(po.getFixedCost());
                    Integer newScale = po.getValidNum() == null ? 2 : po.getValidNum();
//                    BigDecimal result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    BigDecimal result = new BigDecimal("0");
                    if (Objects.equals(po.getPaymentCycle(), 1)) {
                        int monthValue = 1;
                        for (int i = monthIndex - 1; i >= 0; i--) {
                            String cycleValue = po.getCycleSetting().charAt(i) + "";
                            if (Integer.parseInt(cycleValue) == 1) {
                                break;
                            }
                            monthValue++;
                        }
                        if (po.getAccountType() == 1) {
                            paymentNum = paymentNum.multiply(new BigDecimal(monthValue));
                            fixedCost = fixedCost.multiply(new BigDecimal(monthValue));
                            result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                        } else {
                            for (int i = 0; i < monthValue; i++) {
                                result = result.add(SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost)));
                            }
                        }
                    } else {
                        result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    }
                    fundComJsonMap.put(String.valueOf(e), result.toPlainString());
                    fundComList.add(result);
                });
                insuranceAccountDetailPO.setFundComJson(JSON.toJSONString(fundComJsonMap));
                BigDecimal fundComSum = new BigDecimal("0");
                for (BigDecimal bigDecimal : fundComList) {
                    fundComSum = fundComSum.add(bigDecimal);
                }
                insuranceAccountDetailPO.setFundComSum(fundComSum.toPlainString());

            }
        }
        return insuranceAccountDetailPO;
    }


    public InsuranceAccountDetailPO accountSocial(InsuranceAccountDetailPO insuranceAccountDetailPO, InsuranceArchivesAccountPO accountPO, String billMonth, String tenantKey) {
        boolean welBaseDiffSign = siArchivesBiz.isDiffWelBase();
        if (accountPO.getSocial() != null) {
            InsuranceArchivesSocialSchemePO socialPO = accountPO.getSocial();
            insuranceAccountDetailPO.setSocialPayOrg(socialPO.getPaymentOrganization());
            insuranceAccountDetailPO.setSocialAccount(socialPO.getSocialAccount());
            insuranceAccountDetailPO.setSocialSchemeId(socialPO.getSocialSchemeId());
            insuranceAccountDetailPO.setSocialPaymentBaseString(socialPO.getSocialPaymentBaseString());
            insuranceAccountDetailPO.setSocialPaymentComBaseString(socialPO.getSocialPaymentComBaseString());
            //判断是否在起始缴纳月和最后缴纳月之间
            Boolean inDataRange = SalaryDateUtil.monthInRange(insuranceAccountDetailPO.getBillMonth(), socialPO.getSocialStartTime(), socialPO.getSocialEndTime());
            if ((NonPaymentEnum.YES.getValue().equals(socialPO.getNonPayment()) || socialPO.getNonPayment() == null) && socialPO.getSocialSchemeId() != null && inDataRange) {
                List<InsuranceSchemeDetailPO> detailPOS = getInsuranceSchemeDetailMapper().queryListBySchemeId(socialPO.getSocialSchemeId());
                encryptUtil.decryptList(detailPOS, InsuranceSchemeDetailPO.class);
                //方案中包含的需要缴纳社保的个人福利
                int monthIndex = Integer.parseInt(billMonth.split("-")[1]) - 1;
                Map<Long, InsuranceSchemeDetailPO> schemeperson = detailPOS.stream()
                        .filter(item ->
                                Objects.equals(IsPaymentEnum.YES.getValue(), item.getIsPayment()) &&
                                        Objects.equals(item.getPaymentScope(), PaymentScopeEnum.SCOPE_PERSON.getValue()) &&
                                        (item.getPaymentCycle() == null || item.getPaymentCycle() == 0 || (item.getPaymentCycle() == 1 && String.valueOf(item.getCycleSetting().charAt(monthIndex)).equals("1")))
                        )
                        .collect(
                                Collectors.toMap(InsuranceSchemeDetailPO::getInsuranceId, Function.identity()));
                //档案中包含的基数信息
                HashMap<String, String> archivesPerson = JSON.parseObject(socialPO.getSocialPaymentBaseString(), new HashMap<String, String>().getClass());
                //需要核算社保的福利id  个人
                List<Long> needArchivesPerson = new ArrayList<>();
                if (archivesPerson != null) {
                    archivesPerson.forEach((id, value) -> {
                        if (schemeperson.containsKey(Long.valueOf(id))) {
                            needArchivesPerson.add(Long.valueOf(id));
                        }
                    });
                }
                //避免福利档案的方案未设置基数，导致核算时遗漏这些福利项的核算，遍历下方案相关福利项，并将遗漏的福利项id添加
                if(schemeperson.size() > 0) {
                    schemeperson.forEach((id, object) -> {
                        if (!needArchivesPerson.contains(id)) {
                            needArchivesPerson.add(id);
                        }
                    });
                }
                //判断核算周期、核算月、福利起始缴纳月的关系
                checkCycleSettingWithStartMonth(schemeperson, billMonth, socialPO.getSocialStartTime());

                List<BigDecimal> socialPer = new ArrayList<>();
                Map<String, String> socialPerJsonMap = new HashMap<>();
                needArchivesPerson.forEach(e -> {
                    InsuranceSchemeDetailPO po = schemeperson.get(e);
                    BigDecimal paymentProportion = new BigDecimal(StringUtils.isBlank(po.getPaymentProportion()) ? "0" : po.getPaymentProportion()).divide(new BigDecimal("100"));
                    BigDecimal paymentNum = new BigDecimal((ObjectUtil.isEmpty(archivesPerson) || StringUtils.isBlank(archivesPerson.get(String.valueOf(e)))) ? "0" : archivesPerson.get(String.valueOf(e)));
                    BigDecimal fixedCost = StringUtils.isBlank(po.getFixedCost()) ? new BigDecimal("0") : new BigDecimal(po.getFixedCost());
                    Integer newScale = po.getValidNum() == null ? 2 : po.getValidNum();
//                    BigDecimal result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    BigDecimal result = new BigDecimal("0");
                    if (Objects.equals(po.getPaymentCycle(), 1)) {
                        int monthValue = 1;
                        for (int i = monthIndex - 1; i >= 0; i--) {
                            String cycleValue = po.getCycleSetting().charAt(i) + "";
                            if (Integer.parseInt(cycleValue) == 1) {
                                break;
                            }
                            monthValue++;
                        }
                        if (po.getAccountType() == 1) {
                            paymentNum = paymentNum.multiply(new BigDecimal(monthValue));
                            fixedCost = fixedCost.multiply(new BigDecimal(monthValue));
                            result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                        } else {
                            for (int i = 0; i < monthValue; i++) {
                                result = result.add(SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost)));
                            }
                        }
                    } else {
                        result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    }
                    socialPerJsonMap.put(String.valueOf(e), result.toPlainString());
                    socialPer.add(result);
                });
                insuranceAccountDetailPO.setSocialPerJson(JSON.toJSONString(socialPerJsonMap));
                BigDecimal socialPerSum = new BigDecimal("0");
                for (BigDecimal bigDecimal : socialPer) {
                    socialPerSum = socialPerSum.add(bigDecimal);
                }
                insuranceAccountDetailPO.setSocialPerSum(socialPerSum.toPlainString());

                //方案中包含的需要缴纳社保的单位福利
                Map<Long, InsuranceSchemeDetailPO> schemeCom = detailPOS.stream()
                        .filter(item -> Objects.equals(IsPaymentEnum.YES.getValue(), item.getIsPayment()) && Objects.equals(item.getPaymentScope(), PaymentScopeEnum.SCOPE_COMPANY.getValue()) &&
                                (item.getPaymentCycle() == null || item.getPaymentCycle() == 0 || (item.getPaymentCycle() == 1 && String.valueOf(item.getCycleSetting().charAt(monthIndex)).equals("1"))))
                        .collect(
                                Collectors.toMap(InsuranceSchemeDetailPO::getInsuranceId, Function.identity()));
                //档案中包含的基数信息
//                HashMap<String, String> archivesCom = JSON.parseObject(socialPO.getSocialPaymentBaseString(), new HashMap<String, String>().getClass());
                HashMap<String, String> archivesCom = new HashMap<>();
                if (welBaseDiffSign) {
                    archivesCom = JSON.parseObject(socialPO.getSocialPaymentComBaseString(), new HashMap<String, String>().getClass());
                } else {
                    archivesCom = JSON.parseObject(socialPO.getSocialPaymentBaseString(), new HashMap<String, String>().getClass());
                }
                //需要核算社保的福利id  单位
                List<Long> needArchivesCom = new ArrayList<>();
                if (archivesCom != null) {
                    archivesCom.forEach((id, value) -> {
                        if (schemeCom.containsKey(Long.valueOf(id))) {
                            needArchivesCom.add(Long.valueOf(id));
                        }
                    });
                }
                //避免福利档案的方案未设置基数，导致核算时遗漏这些福利项的核算，遍历下方案相关福利项，并将遗漏的福利项id添加
                if(schemeCom.size() > 0) {
                    schemeCom.forEach((id, object) -> {
                        if (!needArchivesCom.contains(id)) {
                            needArchivesCom.add(id);
                        }
                    });
                }
                //判断核算周期、核算月、福利起始缴纳月的关系
                checkCycleSettingWithStartMonth(schemeCom, billMonth, socialPO.getSocialStartTime());

                List<BigDecimal> socialCom = new ArrayList<>();
                Map<String, String> sociaComJsonMap = new HashMap<>();
                HashMap<String, String> finalArchivesCom = archivesCom;
                needArchivesCom.stream().forEach(e -> {
                    InsuranceSchemeDetailPO po = schemeCom.get(e);
                    BigDecimal paymentProportion = new BigDecimal(StringUtils.isBlank(po.getPaymentProportion()) ? "0" : po.getPaymentProportion()).divide(new BigDecimal("100"));
                    BigDecimal paymentNum = new BigDecimal((ObjectUtil.isEmpty(finalArchivesCom) || StringUtils.isBlank(finalArchivesCom.get(String.valueOf(e)))) ? "0" : finalArchivesCom.get(String.valueOf(e)));
                    BigDecimal fixedCost = StringUtils.isBlank(po.getFixedCost()) ? new BigDecimal("0") : new BigDecimal(po.getFixedCost());
                    Integer newScale = po.getValidNum() == null ? 2 : po.getValidNum();
//                    BigDecimal result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    BigDecimal result = new BigDecimal("0");
                    if (Objects.equals(po.getPaymentCycle(), 1)) {
                        int monthValue = 1;
                        for (int i = monthIndex - 1; i >= 0; i--) {
                            String cycleValue = po.getCycleSetting().charAt(i) + "";
                            if (Integer.parseInt(cycleValue) == 1) {
                                break;
                            }
                            monthValue++;
                        }
                        if (po.getAccountType() == 1) {
                            paymentNum = paymentNum.multiply(new BigDecimal(monthValue));
                            fixedCost = fixedCost.multiply(new BigDecimal(monthValue));
                            result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                        } else {
                            for (int i = 0; i < monthValue; i++) {
                                result = result.add(SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost)));
                            }
                        }
                    } else {
                        result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    }
                    sociaComJsonMap.put(String.valueOf(e), result.toPlainString());
                    socialCom.add(result);

                });
                insuranceAccountDetailPO.setSocialComJson(JSON.toJSONString(sociaComJsonMap));
                BigDecimal socialComSum = new BigDecimal("0");
                for (BigDecimal decimal : socialCom) {
                    socialComSum = socialComSum.add(decimal);
                }
                insuranceAccountDetailPO.setSocialComSum(socialComSum.toPlainString());
            }

        }
        return insuranceAccountDetailPO;
    }

    /**
     * 对于核算月和福利起始缴纳月处于同年时，要避免根据周期缴纳福利费用时，可能出现的多余费用缴纳情况
     * @param schemeDetail 福利方案明细
     * @param billMonth 核算月
     * @param startMonth 福利起始缴纳月
     * @return
     */
    public Map<Long, InsuranceSchemeDetailPO> checkCycleSettingWithStartMonth(Map<Long, InsuranceSchemeDetailPO> schemeDetail, String billMonth, String startMonth) {
        String billYear = billMonth.substring(0,4);
        if (StringUtils.isNotBlank(startMonth) && billYear.equals(startMonth.substring(0,4))) {
            int startMonthIndex = Integer.parseInt(startMonth.split("-")[1]) - 1;
            schemeDetail.forEach((k, v) -> {
                if (v.getPaymentCycle() != null && v.getPaymentCycle().equals(1) && startMonthIndex != 0) {
                    StringBuilder newCycleSetting = new StringBuilder(v.getCycleSetting());
                    newCycleSetting.setCharAt(startMonthIndex - 1, '1');
                    v.setCycleSetting(newCycleSetting.toString());
                }
            });

        }
        return schemeDetail;
    }

    public void batchSaveAccountInspectDetail(List<InsuranceAccountDetailPO> list, String billMonth, String tenantKey) {
        List<InsuranceAccountInspectPO> insuranceAccountInspectAllPOS = accountInspect(list, true);
        batchDelInspectDetail(insuranceAccountInspectAllPOS);
        List<InsuranceAccountInspectPO> insuranceAccountInspectPOS = accountInspect(list, false);
        if (CollectionUtils.isNotEmpty(insuranceAccountInspectPOS)) {
            batchSaveInspectDetail(insuranceAccountInspectPOS);
        }
    }

    public List<InsuranceAccountInspectPO> accountInspect(List<InsuranceAccountDetailPO> list, boolean isAll) {
        List<InsuranceAccountInspectPO> insuranceAccountInspectPOS = new ArrayList<>();
        for (InsuranceAccountDetailPO e : list) {
            if (isAll || detailCheck(e.getSocialPerJson()) || detailCheck(e.getSocialComJson())
                    || detailCheck(e.getFundPerJson()) || detailCheck(e.getFundComJson())
                    || detailCheck(e.getOtherPerJson()) || detailCheck(e.getOtherComJson())) {
                InsuranceAccountInspectPO insuranceAccountInspectPO = InsuranceAccountInspectPO.builder().build();
                insuranceAccountInspectPO.setSupplementaryProjects(e.getSupplementaryProjects());
                insuranceAccountInspectPO.setInspectStatus(InspectStatusEnum.IGNORE.getValue());
                insuranceAccountInspectPO.setBillMonth(e.getBillMonth());
                insuranceAccountInspectPO.setCreator(e.getCreator());
                insuranceAccountInspectPO.setCreateTime(new Date());
                insuranceAccountInspectPO.setDeleteType(DeleteTypeEnum.NOT_DELETED.getValue());
                insuranceAccountInspectPO.setEmployeeId(e.getEmployeeId());
                insuranceAccountInspectPO.setPaymentStatus(e.getPaymentStatus());
                insuranceAccountInspectPO.setSupplementaryMonth(e.getSupplementaryMonth());
                insuranceAccountInspectPO.setTenantKey(e.getTenantKey());
                insuranceAccountInspectPO.setUpdateTime(new Date());
                insuranceAccountInspectPOS.add(insuranceAccountInspectPO);
            }
        }
        return insuranceAccountInspectPOS;
    }


    public boolean detailCheck(String baseString) {
        if (StringUtils.isEmpty(baseString)) {
            return false;
        }
        Map<String, String> baseStringMap = JSON.parseObject(baseString, new TypeReference<Map<String, String>>() {
        });
        if (baseStringMap == null || baseStringMap.size() == 0) {
            return false;
        }
        return baseStringMap.values().stream().anyMatch(item -> StringUtils.isEmpty(item) || Pattern.matches("^([0].?[0]*)$", item));

    }

    public void batchDelInspectDetail(List<InsuranceAccountInspectPO> list) {
        List<List<InsuranceAccountInspectPO>> lists = Lists.partition(list, 100);
        lists.forEach(getInsuranceAccountInspectMapper()::batchDelInspectDetails);

    }

    public void batchSaveInspectDetail(List<InsuranceAccountInspectPO> list) {
        List<List<InsuranceAccountInspectPO>> lists = Lists.partition(list, 100);
        lists.forEach(getInsuranceAccountInspectMapper()::batchSaveInspectDetails);
    }


    /**
     * 跟新台账接口
     *
     * @param tenantKey 租户key
     */
    public void updateBatchAccount(AccountParam param, Long employeeId, String tenantKey, String currentUserName) {
        String billMonth = param.getBillMonth();

        List<InsuranceAccountDetailPO> insuranceAccountDetailPOS = getInsuranceAccountDetailMapper().selectList(billMonth, param.getPaymentOrganization());
        Map<Long, List<InsuranceAccountDetailPO>> map = insuranceAccountDetailPOS.stream().filter(item -> item.getEmployeeId() != null)
                .collect(Collectors.groupingBy(InsuranceAccountDetailPO::getEmployeeId));
        int socialAccountPerson = 0;
        int funcAccountPerson = 0;
        int otherAccountPerson = 0;
        BigDecimal socialSum = new BigDecimal("0");
        BigDecimal fundSum = new BigDecimal("0");
        BigDecimal otherSum = new BigDecimal("0");
        for (Map.Entry<Long, List<InsuranceAccountDetailPO>> entry : map.entrySet()) {
            List<InsuranceAccountDetailPO> v = entry.getValue();
            BigDecimal socialTemp = new BigDecimal("0");
            BigDecimal fundTemp = new BigDecimal("0");
            BigDecimal otherTemp = new BigDecimal("0");
            encryptUtil.decryptList(v, InsuranceAccountDetailPO.class);
            boolean socialPersonFlag = false;
            boolean fundPersonFlag = false;
            boolean otherPersonFlag = false;
            for (InsuranceAccountDetailPO item : v) {
                // 判断社保是否为0
                socialPersonFlag = (StringUtils.isBlank(item.getSocialSum()) || SalaryEntityUtil.StringEqZERO(item.getSocialSum()));
                BigDecimal socialPerson = socialPersonFlag ? new BigDecimal("0") : new BigDecimal(item.getSocialSum());
                fundPersonFlag = (StringUtils.isBlank(item.getFundSum()) || SalaryEntityUtil.StringEqZERO(item.getFundSum()));
                BigDecimal fundPerson = fundPersonFlag ? new BigDecimal("0") : new BigDecimal(item.getFundSum());
                otherPersonFlag = (StringUtils.isBlank(item.getOtherSum()) || SalaryEntityUtil.StringEqZERO(item.getOtherSum()));
                BigDecimal otherPerson = otherPersonFlag ? new BigDecimal("0") : new BigDecimal(item.getOtherSum());
                socialTemp = socialTemp.add(socialPerson);
                fundTemp = fundTemp.add(fundPerson);
                otherTemp = otherTemp.add(otherPerson);
                if (!socialPersonFlag && !item.getPaymentStatus().equals(PaymentStatusEnum.BALANCE.getValue())) {
                    socialAccountPerson += 1;
                }
                if (!fundPersonFlag && !item.getPaymentStatus().equals(PaymentStatusEnum.BALANCE.getValue())) {
                    funcAccountPerson += 1;
                }
                if (!otherPersonFlag && !item.getPaymentStatus().equals(PaymentStatusEnum.BALANCE.getValue())) {
                    otherAccountPerson += 1;
                }
            }
//            if (!socialPersonFlag) {
//                socialSum = socialSum.add(socialTemp);
//            }
//            if (!fundPersonFlag) {
//                fundSum = fundSum.add(fundTemp);
//            }
//            if (!otherPersonFlag) {
//                otherSum = otherSum.add(otherTemp);
//            }

            if (!"0".equals(socialTemp.toPlainString())) {
                socialSum = socialSum.add(socialTemp);
            }
            if (!"0".equals(fundTemp.toPlainString())) {
                fundSum = fundSum.add(fundTemp);
            }
            if (!"0".equals(otherTemp.toPlainString())) {
                otherSum = otherSum.add(otherTemp);
            }
        }
        InsuranceAccountBatchPO insuranceAccountBatchPO = getInsuranceAccountBatchMapper().getByBillMonth(billMonth, param.getPaymentOrganization());
        encryptUtil.decrypt(insuranceAccountBatchPO, InsuranceAccountBatchPO.class);

        insuranceAccountBatchPO.setAccountant(currentUserName);
        insuranceAccountBatchPO.setUpdateTime(new Date());
        insuranceAccountBatchPO.setSocialPay(socialSum.toPlainString());
        insuranceAccountBatchPO.setSocialNum(socialAccountPerson);
        insuranceAccountBatchPO.setFundNum(funcAccountPerson);
        insuranceAccountBatchPO.setFundPay(fundSum.toPlainString());
        insuranceAccountBatchPO.setOtherNum(otherAccountPerson);
        insuranceAccountBatchPO.setOtherPay(otherSum.toPlainString());
        encryptUtil.encrypt(insuranceAccountBatchPO, InsuranceAccountBatchPO.class);
        getInsuranceAccountBatchMapper().updateById(insuranceAccountBatchPO);
//        LoggerContext insuranceSchemeContext = new LoggerContext();
//        insuranceSchemeContext.setTargetId(String.valueOf(insuranceAccountBatchPO.getId()));
//        insuranceSchemeContext.setTargetName(insuranceAccountBatchPO.getBillMonth());
//        insuranceSchemeContext.setOperateType(OperateTypeEnum.UPDATE.getValue());
//        insuranceSchemeContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(tenantKey, employeeId, 100491, "更新台账"));
//        insuranceSchemeContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(tenantKey, employeeId, 100491, "更新台账"));
//        insuranceSchemeContext.setNewValues(insuranceAccountBatchPO);
//        siAccountLoggerTemplate.write(insuranceSchemeContext);

    }


    public void saveCommonAccount(SaveCommonAccountParam param, Long employeeId, String currentUserName) {
        List<Long> collect;
        SalaryAssert.notEmpty(param.getIncludes(), SalaryI18nUtil.getI18nLabel(100466, "参数为空"));
        SalaryAssert.notNull(param.getBillMonth(), SalaryI18nUtil.getI18nLabel(100467, "账单月为空"));
        if (CollectionUtils.isNotEmpty(param.getExcludes())) {
            collect = param.getIncludes().stream().filter(item -> !param.getExcludes().contains(item)).collect(Collectors.toList());
        } else {
            collect = param.getIncludes();
        }
        SalaryAssert.notEmpty(collect, SalaryI18nUtil.getI18nLabel(99920, "无核算人员"));
        AccountParam accountParam = new AccountParam();
        accountParam.setBillMonth(param.getBillMonth());
        accountParam.setIds(collect);
        accounting(accountParam, employeeId, SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY, currentUserName);
    }

    public void delete(AccountParam param, Long employeeId) {
        InsuranceAccountBatchPO insuranceAccountBatchPO = getInsuranceAccountBatchMapper().getByBillMonth(param.getBillMonth(), param.getPaymentOrganization());
        encryptUtil.decrypt(insuranceAccountBatchPO, InsuranceAccountBatchPO.class);
        SalaryAssert.notNull(insuranceAccountBatchPO, SalaryI18nUtil.getI18nLabel(84026, "参数错误"));
//        if (insuranceAccountBatchPO.getBillStatus().equals(BillStatusEnum.ARCHIVED.getValue())) {
//            int num = checkIfBusinessaccounting(insuranceAccountBatchPO);
//            //表示已经被核算过不能重新核算
//            if (num > 0) {
//                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(0, "已被薪酬核算给核算过，无法删除！"));
//            }
//        }

//        if(param.getPaymentOrganization()==null){
//            throw new SalaryRunTimeException("个税扣缴义务人为空");
//        }
        getInsuranceAccountBatchMapper().deleteById(insuranceAccountBatchPO.getId());
        getInsuranceAccountDetailMapper().batchDeleteNotFile(param.getBillMonth(), param.getPaymentOrganization());

        //删除账单月份+个税扣缴义务人下的调差数据
        getInsuranceCompensationMapper().deleteByBillMonthAndPayOrg(param.getBillMonth(), param.getPaymentOrganization());
//        LoggerContext insuranceSchemeContext = new LoggerContext();
//        insuranceSchemeContext.setTargetId(String.valueOf(insuranceAccountBatchPO.getId()));
//        insuranceSchemeContext.setTargetName(insuranceAccountBatchPO.getBillMonth());
//        insuranceSchemeContext.setOperateType(OperateTypeEnum.DELETE.getValue());
//        insuranceSchemeContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(tenantkey, employeeId, 100464, "删除台账"));
//        insuranceSchemeContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(tenantkey, employeeId, 100464, "删除台账"));
//        insuranceSchemeContext.setNewValues(insuranceAccountBatchPO);
//        siAccountLoggerTemplate.write(insuranceSchemeContext);
    }

    public void saveSupplementaryAccount(SaveSupplementaryAccountParam param, Long employeeId, String currentUserName) {
        if (StringUtils.isBlank(param.getBillMonth()) || CollectionUtils.isEmpty(param.getBillMonthList()) || CollectionUtils.isEmpty(param.getProjects())
                || CollectionUtils.isEmpty(param.getIncludes())) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(84026, "参数错误"));
        }
        //需要补缴的月份
        if (param.getBillMonthList().contains(param.getBillMonth())) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100481, "当前月走正常缴纳"));
        }
        //需要补缴的员工id
        List<Long> employeeIds = param.getIncludes();
        if (CollectionUtils.isNotEmpty(param.getExcludes())) {
            employeeIds = employeeIds.stream().filter(item -> !param.getExcludes().contains(item)).collect(Collectors.toList());
        }
        //校验补缴人员是否存在福利档案基础信息，并且runStatus处于正在缴纳或者待减员
        List<InsuranceArchivesBaseInfoPO> insuranceBaseInfoList = getInsuranceBaseInfoMapper().getSocialByPaymentOrganization(param.getPaymentOrganization());
        List<Long> finalEmployeeIds = employeeIds;
        List<InsuranceArchivesBaseInfoPO> filterList = insuranceBaseInfoList.stream().filter(e -> {
            for (Long uId : finalEmployeeIds) {
                if (e.getEmployeeId().equals(uId) && (e.getRunStatus().equals(EmployeeStatusEnum.STAY_DEL.getValue()) || e.getRunStatus().equals(EmployeeStatusEnum.PAYING.getValue()))) {
                    return true;
                }
            }
            return false;
        }).collect(Collectors.toList());
        if (filterList.size() != employeeIds.size()) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(0, "补缴人员中存在未设置福利档案人员或相关人员不在福利在缴人员中，不可新建补缴信息！"));
        }
        //20231122逻辑优化，过滤出不在起始缴纳月和最后缴纳月区间的人员
        List<Long> empIdsInPayMonthRange = listCanPayEmpIds(param.getPaymentOrganization(), param.getBillMonth());
        employeeIds = employeeIds.stream().filter(f -> empIdsInPayMonthRange.contains(f)).collect(Collectors.toList());

        SalaryAssert.notEmpty(employeeIds, SalaryI18nUtil.getI18nLabel(99920, "无核算人员"));
        List<SupplementAccountBaseParam> baseList = new ArrayList<>();
        employeeIds.stream().forEach(id -> {
            param.getBillMonthList().stream().forEach(month -> {
                SupplementAccountBaseParam supplementAccountBaseParam = SupplementAccountBaseParam.builder()
                        .supplementaryMonth(month)
                        .employeeId(id)
                        .paymentOrganization(param.getPaymentOrganization())
                        .projects(param.getProjects())
                        .billMonth(param.getBillMonth())
                        .supplementType(param.getSupplementType())
                        .build();
                if ("2".equals(param.getSupplementType())) {
                    supplementAccountBaseParam.setSocialPaymentBaseString(param.getSocialPaymentBaseString());
                    supplementAccountBaseParam.setFundPaymentBaseString(param.getFundPaymentBaseString());
                    supplementAccountBaseParam.setOtherPaymentBaseString(param.getOtherPaymentBaseString());
                } else if("3".equals(param.getSupplementType())) {
                    supplementAccountBaseParam.setSocialPaymentPerString(param.getSocialPaymentPerString());
                    supplementAccountBaseParam.setSocialPaymentComString(param.getSocialPaymentComString());
                    supplementAccountBaseParam.setFundPaymentPerString(param.getFundPaymentPerString());
                    supplementAccountBaseParam.setFundPaymentComString(param.getFundPaymentComString());
                    supplementAccountBaseParam.setOtherPaymentPerString(param.getOtherPaymentPerString());
                    supplementAccountBaseParam.setOtherPaymentComString(param.getOtherPaymentComString());
                }
                baseList.add(supplementAccountBaseParam);
            });
        });
        //核算开始
        accountSupplement(baseList, employeeIds, param.getBillMonth(), employeeId, param.getPaymentOrganization());

        updateBatchAccount(AccountParam.builder().billMonth(param.getBillMonth()).paymentOrganization(param.getPaymentOrganization()).build(), employeeId, SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY, currentUserName);
    }

    /**
     * @param baseList    员工id-账单月份-补缴月份（单挑）-补缴项 集合
     * @param employeeIds 需要补缴的员工id
     * @return
     */
    public String accountSupplement(List<SupplementAccountBaseParam> baseList, List<Long> employeeIds, String billMonth, Long employeeId, Long paymentOrganization) {
        //(k,v) k-员工id v-员工对应的福利档案数据
        Map<Long, InsuranceArchivesAccountPO> longInsuranceArchivesAccountPOMap = siArchivesBiz.buildBatchAccount(employeeIds, paymentOrganization);
        //核算结果集
        List<InsuranceAccountDetailPO> pos = new ArrayList<>();
        baseList.forEach(baseParam -> {
            //判断人员id+账单月份+补缴月份在表中的唯一性
            List<InsuranceAccountDetailPO> supplementList = getInsuranceAccountDetailMapper().querySupplementList(baseParam.getBillMonth(), baseParam.getPaymentOrganization(), baseParam.getEmployeeId(), baseParam.getSupplementaryMonth());
            if (supplementList.size() > 0) {
                throw new SalaryRunTimeException("当前人员和账单月份已存在该补缴月份的数据！无法再次创建！");
            }
            InsuranceAccountDetailPO insuranceAccountDetailPO = accountSingleEmployeeBill(baseParam, longInsuranceArchivesAccountPOMap.get(baseParam.getEmployeeId()), employeeId);
            pos.add(insuranceAccountDetailPO);
        });
        batchSaveSupplementAccount(pos, billMonth, SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY);
        return SalaryI18nUtil.getI18nLabel(100492, "核算完成,数据保存成功");
    }


    public InsuranceAccountDetailPO accountSingleEmployeeBill(SupplementAccountBaseParam baseParam, InsuranceArchivesAccountPO accountPO, Long employeeId) {
        InsuranceAccountDetailPO insuranceAccountDetailPO = new InsuranceAccountDetailPO();
        List<Integer> projects = baseParam.getProjects();
        insuranceAccountDetailPO.setBillMonth(baseParam.getBillMonth());
        insuranceAccountDetailPO.setBillStatus(BillStatusEnum.NOT_ARCHIVED.getValue());
        insuranceAccountDetailPO.setCreator(employeeId);
        insuranceAccountDetailPO.setCreateTime(new Date());
        insuranceAccountDetailPO.setUpdateTime(new Date());
        insuranceAccountDetailPO.setDeleteType(DeleteTypeEnum.NOT_DELETED.getValue());
        insuranceAccountDetailPO.setId(IdGenerator.generate());
        insuranceAccountDetailPO.setEmployeeId(baseParam.getEmployeeId());
        insuranceAccountDetailPO.setPaymentStatus(PaymentStatusEnum.REPAIR.getValue());
        insuranceAccountDetailPO.setSupplementaryMonth(baseParam.getSupplementaryMonth());
        insuranceAccountDetailPO.setPaymentOrganization(baseParam.getPaymentOrganization());
        insuranceAccountDetailPO.setSupplementaryProjects(
                String.join(",",
                        baseParam.getProjects() == null ? new ArrayList<>() : baseParam.getProjects().stream().map(String::valueOf).collect(Collectors.toList())));
        insuranceAccountDetailPO.setTenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY);
        insuranceAccountDetailPO.setResourceFrom(ResourceFromEnum.SYSTEM.getValue());
        //缴纳组织=个税扣缴义务人
        insuranceAccountDetailPO.setSocialPayOrg(baseParam.getPaymentOrganization());
        if (projects.contains(ProjectTypeEnum.ALL.getValue())) {
            if ("2".equals(baseParam.getSupplementType())) {
                if (accountPO.getSocial() != null) {
                    accountPO.getSocial().setSocialPaymentBaseString(baseParam.getSocialPaymentBaseString());
                }
                if (accountPO.getFund() != null) {
                    accountPO.getFund().setFundPaymentBaseString(baseParam.getFundPaymentBaseString());
                }
                if (accountPO.getOther() != null) {
                    accountPO.getOther().setOtherPaymentBaseString(baseParam.getOtherPaymentBaseString());
                }
                accountSocial(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
                accountFund(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
                accountOther(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
            } else if ("3".equals(baseParam.getSupplementType())) {
                accountSocialByData(insuranceAccountDetailPO, baseParam);
                accountFundByData(insuranceAccountDetailPO, baseParam);
                accountOtherByData(insuranceAccountDetailPO, baseParam);
            } else {
                accountSocial(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
                accountFund(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
                accountOther(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
            }

            return account(insuranceAccountDetailPO);
        }
        if (projects.contains(ProjectTypeEnum.SOCIAL.getValue())) {
            if ("2".equals(baseParam.getSupplementType())) {
                if (accountPO.getSocial() != null) {
                    accountPO.getSocial().setSocialPaymentBaseString(baseParam.getSocialPaymentBaseString());
                }
                accountSocial(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
            } else if ("3".equals(baseParam.getSupplementType())) {
                accountSocialByData(insuranceAccountDetailPO, baseParam);
            } else {
                accountSocial(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
            }

        }
        if (!projects.contains(ProjectTypeEnum.SOCIAL.getValue())) {
            List<Long> ids = new ArrayList<>();
            List<ICategoryPO> list = getICategoryMapper().listByDataType(DataTypeEnum.SYSTEM.getValue());

            if (projects.contains(ProjectTypeEnum.ENDOWMENT_INSURANCE.getValue())) {
                ICategoryPO insuranceCategoryPO = list.stream().filter(item -> SalaryI18nUtil.getI18nLabel(93113, "养老保险").equals(item.getInsuranceName())).findFirst()
                        .get();
                ids.add(insuranceCategoryPO.getId());
            }
            if (projects.contains(ProjectTypeEnum.MEDICAL_INSURANCE.getValue())) {
                ICategoryPO insuranceCategoryPO = list.stream().filter(item -> SalaryI18nUtil.getI18nLabel(93114, "医疗保险").equals(item.getInsuranceName())).findFirst()
                        .get();
                ids.add(insuranceCategoryPO.getId());
            }
            if ("2".equals(baseParam.getSupplementType())) {
                if (accountPO.getSocial() != null) {
                    accountPO.getSocial().setSocialPaymentBaseString(baseParam.getSocialPaymentBaseString());
                }
                accountEndowmentInsurance(insuranceAccountDetailPO, accountPO, ids, baseParam.getSupplementaryMonth());
            } else if ("3".equals(baseParam.getSupplementType())) {
                accountEndowmentInsuranceByData(insuranceAccountDetailPO, baseParam, ids);
            } else {
                accountEndowmentInsurance(insuranceAccountDetailPO, accountPO, ids, baseParam.getSupplementaryMonth());
            }

        }
        if (projects.contains(ProjectTypeEnum.FUND.getValue())) {
            if ("2".equals(baseParam.getSupplementType())) {
                if (accountPO.getFund() != null) {
                    accountPO.getFund().setFundPaymentBaseString(baseParam.getFundPaymentBaseString());
                }
                accountFund(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
            } else if ("3".equals(baseParam.getSupplementType())) {
                accountFundByData(insuranceAccountDetailPO, baseParam);
            } else {
                accountFund(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
            }
        }
        if (projects.contains(ProjectTypeEnum.OTHER.getValue())) {

            if ("2".equals(baseParam.getSupplementType())) {
                if (accountPO.getOther() != null) {
                    accountPO.getOther().setOtherPaymentBaseString(baseParam.getOtherPaymentBaseString());
                }
                accountOther(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
            } else if ("3".equals(baseParam.getSupplementType())) {
                accountOtherByData(insuranceAccountDetailPO, baseParam);
            } else {
                accountOther(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
            }

        }

        return account(insuranceAccountDetailPO);
    }


    public InsuranceAccountDetailPO accountOther(InsuranceAccountDetailPO insuranceAccountDetailPO, InsuranceArchivesAccountPO accountPO, String billMonth) {
        boolean welBaseDiffSign = siArchivesBiz.isDiffWelBase();
        if (accountPO.getOther() != null) {
            InsuranceArchivesOtherSchemePO otherPO = accountPO.getOther();
            insuranceAccountDetailPO.setOtherPayOrg(otherPO.getPaymentOrganization());
            insuranceAccountDetailPO.setOtherSchemeId(otherPO.getOtherSchemeId());
            insuranceAccountDetailPO.setOtherPaymentBaseString(otherPO.getOtherPaymentBaseString());
            insuranceAccountDetailPO.setOtherPaymentComBaseString(otherPO.getOtherPaymentComBaseString());
            //判断是否在起始缴纳月和最后缴纳月之间
            Boolean inDataRange = SalaryDateUtil.monthInRange(billMonth, otherPO.getOtherStartTime(), otherPO.getOtherEndTime());
            if ((Objects.equals(NonPaymentEnum.YES.getValue(), otherPO.getNonPayment()) || otherPO.getNonPayment() == null) && otherPO.getOtherSchemeId() != null && inDataRange) {
                List<InsuranceSchemeDetailPO> detailPOS = getInsuranceSchemeDetailMapper().queryListBySchemeId(otherPO.getOtherSchemeId());
                encryptUtil.decryptList(detailPOS, InsuranceSchemeDetailPO.class);
                //方案中包含的需要缴纳其他的个人福利
                int monthIndex = Integer.parseInt(billMonth.split("-")[1]) - 1;
                Map<Long, InsuranceSchemeDetailPO> otherPerson = detailPOS.stream()
                        .filter(item -> Objects.equals(IsPaymentEnum.YES.getValue(), item.getIsPayment()) && Objects.equals(item.getPaymentScope(), PaymentScopeEnum.SCOPE_PERSON.getValue()) && (item.getPaymentCycle() == null || item.getPaymentCycle() == 0 || (item.getPaymentCycle() == 1 && String.valueOf(item.getCycleSetting().charAt(monthIndex)).equals("1"))))
                        .collect(
                                Collectors.toMap(InsuranceSchemeDetailPO::getInsuranceId, Function.identity()));
                //档案中包含的基数信息
                HashMap<String, String> archivesPerson = JSON.parseObject(otherPO.getOtherPaymentBaseString(), new HashMap<String, String>().getClass());
                //需要核算其他的福利id  个人
                List<Long> needArchivesPerson = new ArrayList<>();
                if (archivesPerson != null) {
                    archivesPerson.forEach((id, value) -> {
                        if (otherPerson.containsKey(Long.valueOf(id))) {
                            needArchivesPerson.add(Long.valueOf(id));
                        }
                    });
                }
                //判断核算周期、核算月、福利起始缴纳月的关系
                checkCycleSettingWithStartMonth(otherPerson, billMonth, otherPO.getOtherStartTime());

                List<BigDecimal> otherPer = new ArrayList<>();
                Map<String, String> otherPerJsonMap = new HashMap<>();
                needArchivesPerson.stream().forEach(e -> {
                    InsuranceSchemeDetailPO po = otherPerson.get(e);
                    BigDecimal paymentProportion = new BigDecimal(StringUtils.isBlank(po.getPaymentProportion()) ? "0" : po.getPaymentProportion()).divide(new BigDecimal("100"));
                    BigDecimal paymentNum = new BigDecimal((ObjectUtil.isEmpty(archivesPerson) || StringUtils.isBlank(archivesPerson.get(String.valueOf(e)))) ? "0" : archivesPerson.get(String.valueOf(e)));
                    BigDecimal fixedCost = StringUtils.isBlank(po.getFixedCost()) ? new BigDecimal("0") : new BigDecimal(po.getFixedCost());
                    Integer newScale = po.getValidNum() == null ? 2 : po.getValidNum();
//                    BigDecimal result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    BigDecimal result = new BigDecimal("0");
                    if (po.getPaymentCycle() != null && po.getPaymentCycle() == 1) {
                        int monthValue = 1;
                        for (int i = monthIndex - 1; i >= 0; i--) {
                            String cycleValue = po.getCycleSetting().charAt(i) + "";
                            if (Integer.parseInt(cycleValue) == 1) {
                                break;
                            }
                            monthValue++;
                        }
                        if (po.getAccountType() == 1) {
                            paymentNum = paymentNum.multiply(new BigDecimal(monthValue));
                            fixedCost = fixedCost.multiply(new BigDecimal(monthValue));
                            result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                        } else {
                            for (int i = 0; i < monthValue; i++) {
                                result = result.add(SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost)));
                            }
                        }
                    } else {
                        result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    }

                    otherPerJsonMap.put(String.valueOf(e), result.toPlainString());
                    otherPer.add(result);
                });
                insuranceAccountDetailPO.setOtherPerJson(JSON.toJSONString(otherPerJsonMap));
                BigDecimal otherPerSum = new BigDecimal("0");
                for (BigDecimal bigDecimal : otherPer) {
                    otherPerSum = otherPerSum.add(bigDecimal);
                }
                insuranceAccountDetailPO.setOtherPerSum(otherPerSum.toPlainString());

                //方案中包含的需要缴纳公积金的单位福利
                Map<Long, InsuranceSchemeDetailPO> otherCom = detailPOS.stream()
                        .filter(
                                item -> Objects.equals(IsPaymentEnum.YES.getValue(), item.getIsPayment()) && Objects.equals(item.getPaymentScope(), PaymentScopeEnum.SCOPE_COMPANY.getValue()) && (item.getPaymentCycle() == null || item.getPaymentCycle() == 0 || (item.getPaymentCycle() == 1 && String.valueOf(item.getCycleSetting().charAt(monthIndex)).equals("1"))))
                        .collect(
                                Collectors.toMap(InsuranceSchemeDetailPO::getInsuranceId, Function.identity()));
                //档案中包含的基数信息
//                HashMap<String, String> archivesCom = JSON.parseObject(otherPO.getOtherPaymentBaseString(), new HashMap<String, String>().getClass());
                HashMap<String, String> archivesCom = new HashMap<>();
                if (welBaseDiffSign) {
                    archivesCom = JSON.parseObject(otherPO.getOtherPaymentComBaseString(), new HashMap<String, String>().getClass());
                } else {
                    archivesCom = JSON.parseObject(otherPO.getOtherPaymentBaseString(), new HashMap<String, String>().getClass());
                }
                //需要核算其他的福利id  单位
                List<Long> needArchivesCom = new ArrayList<>();
                if (archivesCom != null) {
                    archivesCom.forEach((id, value) -> {
                        if (otherCom.containsKey(Long.valueOf(id))) {
                            needArchivesCom.add(Long.valueOf(id));
                        }
                    });
                }
                //判断核算周期、核算月、福利起始缴纳月的关系
                checkCycleSettingWithStartMonth(otherCom, billMonth, otherPO.getOtherStartTime());

                List<BigDecimal> otherComList = new ArrayList<>();
                Map<String, String> otherComJsonMap = new HashMap<>();
                HashMap<String, String> finalArchivesCom = archivesCom;
                needArchivesCom.stream().forEach(e -> {
                    InsuranceSchemeDetailPO po = otherCom.get(e);
                    BigDecimal paymentProportion = new BigDecimal(StringUtils.isBlank(po.getPaymentProportion()) ? "0" : po.getPaymentProportion()).divide(new BigDecimal("100"));
                    BigDecimal paymentNum = new BigDecimal((ObjectUtil.isEmpty(finalArchivesCom) || StringUtils.isBlank(finalArchivesCom.get(String.valueOf(e)))) ? "0" : finalArchivesCom.get(String.valueOf(e)));
                    BigDecimal fixedCost = StringUtils.isBlank(po.getFixedCost()) ? new BigDecimal("0") : new BigDecimal(po.getFixedCost());
                    Integer newScale = po.getValidNum() == null ? 2 : po.getValidNum();
//                    BigDecimal result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    BigDecimal result = new BigDecimal("0");
                    if (Objects.equals(po.getPaymentCycle(), 1)) {
                        int monthValue = 1;
                        for (int i = monthIndex - 1; i >= 0; i--) {
                            String cycleValue = po.getCycleSetting().charAt(i) + "";
                            if (Integer.parseInt(cycleValue) == 1) {
                                break;
                            }
                            monthValue++;
                        }
                        if (po.getAccountType() == 1) {
                            paymentNum = paymentNum.multiply(new BigDecimal(monthValue));
                            fixedCost = fixedCost.multiply(new BigDecimal(monthValue));
                            result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                        } else {
                            for (int i = 0; i < monthValue; i++) {
                                result = result.add(SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost)));
                            }
                        }
                    } else {
                        result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    }

                    otherComJsonMap.put(String.valueOf(e), result.toPlainString());
                    otherComList.add(result);
                });
                insuranceAccountDetailPO.setOtherComJson(JSON.toJSONString(otherComJsonMap));
                BigDecimal otherComSum = new BigDecimal("0");
                for (BigDecimal bigDecimal : otherComList) {
                    otherComSum = otherComSum.add(bigDecimal);
                }
                insuranceAccountDetailPO.setOtherComSum(otherComSum.toPlainString());
            }
        }
        return insuranceAccountDetailPO;
    }

    public InsuranceAccountDetailPO accountFund(InsuranceAccountDetailPO insuranceAccountDetailPO, InsuranceArchivesAccountPO accountPO, String billMonth) {
        boolean welBaseDiffSign = siArchivesBiz.isDiffWelBase();
        if (accountPO.getFund() != null) {
            InsuranceArchivesFundSchemePO fundPO = accountPO.getFund();
            insuranceAccountDetailPO.setFundPayOrg(fundPO.getPaymentOrganization());
            insuranceAccountDetailPO.setFundAccount(fundPO.getFundAccount());
            insuranceAccountDetailPO.setSupplementFundAccount(fundPO.getSupplementFundAccount());
            insuranceAccountDetailPO.setFundSchemeId(fundPO.getFundSchemeId());
            insuranceAccountDetailPO.setFundPaymentBaseString(fundPO.getFundPaymentBaseString());
            insuranceAccountDetailPO.setFundPaymentComBaseString(fundPO.getFundPaymentComBaseString());
            //判断是否在起始缴纳月和最后缴纳月之间
            Boolean inDataRange = SalaryDateUtil.monthInRange(billMonth, fundPO.getFundStartTime(), fundPO.getFundEndTime());
            if ((Objects.equals(NonPaymentEnum.YES.getValue(), fundPO.getNonPayment()) || fundPO.getNonPayment() == null) && fundPO.getFundSchemeId() != null && inDataRange) {
                List<InsuranceSchemeDetailPO> detailPOS = getInsuranceSchemeDetailMapper().queryListBySchemeId(fundPO.getFundSchemeId());
                encryptUtil.decryptList(detailPOS, InsuranceSchemeDetailPO.class);
                //方案中包含的需要缴纳社保的个人福利
                int monthIndex = Integer.parseInt(billMonth.split("-")[1]) - 1;
                Map<Long, InsuranceSchemeDetailPO> fundperson = detailPOS.stream()
                        .filter(item -> Objects.equals(IsPaymentEnum.YES.getValue(), item.getIsPayment()) && Objects.equals(item.getPaymentScope(), PaymentScopeEnum.SCOPE_PERSON.getValue()) && (item.getPaymentCycle() == null || item.getPaymentCycle() == 0 || (item.getPaymentCycle() == 1 && String.valueOf(item.getCycleSetting().charAt(monthIndex)).equals("1"))))
                        .collect(
                                Collectors.toMap(InsuranceSchemeDetailPO::getInsuranceId, Function.identity()));
                //档案中包含的基数信息
                HashMap<String, String> archivesPerson = JSON.parseObject(fundPO.getFundPaymentBaseString(), new HashMap<String, String>().getClass());
                //需要核算公积金的福利id  个人
                List<Long> needArchivesPerson = new ArrayList<>();
                if (archivesPerson != null) {
                    archivesPerson.forEach((id, value) -> {
                        if (fundperson.containsKey(Long.valueOf(id))) {
                            needArchivesPerson.add(Long.valueOf(id));
                        }
                    });
                }
                //判断核算周期、核算月、福利起始缴纳月的关系
                checkCycleSettingWithStartMonth(fundperson, billMonth, fundPO.getFundStartTime());

                List<BigDecimal> fundPer = new ArrayList<>();
                Map<String, String> fundPerJsonMap = new HashMap<>();
                needArchivesPerson.stream().forEach(e -> {
                    InsuranceSchemeDetailPO po = fundperson.get(e);
                    BigDecimal paymentProportion = new BigDecimal(StringUtils.isBlank(po.getPaymentProportion()) ? "0" : po.getPaymentProportion()).divide(new BigDecimal("100"));
                    BigDecimal paymentNum = new BigDecimal((ObjectUtil.isEmpty(archivesPerson) || StringUtils.isBlank(archivesPerson.get(String.valueOf(e)))) ? "0" : archivesPerson.get(String.valueOf(e)));
                    BigDecimal fixedCost = StringUtils.isBlank(po.getFixedCost()) ? new BigDecimal("0") : new BigDecimal(po.getFixedCost());
                    Integer newScale = po.getValidNum() == null ? 2 : po.getValidNum();
//                    BigDecimal result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    BigDecimal result = new BigDecimal("0");
                    if (Objects.equals(po.getPaymentCycle(), 1)) {
                        int monthValue = 1;
                        for (int i = monthIndex - 1; i >= 0; i--) {
                            String cycleValue = po.getCycleSetting().charAt(i) + "";
                            if (Integer.parseInt(cycleValue) == 1) {
                                break;
                            }
                            monthValue++;
                        }
                        if (po.getAccountType() == 1) {
                            paymentNum = paymentNum.multiply(new BigDecimal(monthValue));
                            fixedCost = fixedCost.multiply(new BigDecimal(monthValue));
                            result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                        } else {
                            for (int i = 0; i < monthValue; i++) {
                                result = result.add(SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost)));
                            }
                        }
                    } else {
                        result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    }

                    fundPerJsonMap.put(String.valueOf(e), result.toPlainString());
                    fundPer.add(result);
                });
                insuranceAccountDetailPO.setFundPerJson(JSON.toJSONString(fundPerJsonMap));
                BigDecimal funPerSum = new BigDecimal("0");
                for (BigDecimal bigDecimal : fundPer) {
                    funPerSum = funPerSum.add(bigDecimal);
                }
                insuranceAccountDetailPO.setFundPerSum(funPerSum.toPlainString());

                //方案中包含的需要缴纳公积金的单位福利
                Map<Long, InsuranceSchemeDetailPO> fundCom = detailPOS.stream()
                        .filter(item -> Objects.equals(IsPaymentEnum.YES.getValue(), item.getIsPayment()) && Objects.equals(item.getPaymentScope(), PaymentScopeEnum.SCOPE_COMPANY.getValue()) && (item.getPaymentCycle() == null || item.getPaymentCycle() == 0 || (item.getPaymentCycle() == 1 && String.valueOf(item.getCycleSetting().charAt(monthIndex)).equals("1"))))
                        .collect(
                                Collectors.toMap(InsuranceSchemeDetailPO::getInsuranceId, Function.identity()));
                //档案中包含的基数信息
//                HashMap<String, String> archivesCom = JSON.parseObject(fundPO.getFundPaymentBaseString(), new HashMap<String, String>().getClass());
                HashMap<String, String> archivesCom = new HashMap<>();
                if (welBaseDiffSign) {
                    archivesCom = JSON.parseObject(fundPO.getFundPaymentComBaseString(), new HashMap<String, String>().getClass());
                } else {
                    archivesCom = JSON.parseObject(fundPO.getFundPaymentBaseString(), new HashMap<String, String>().getClass());
                }
                //需要核算公积金的福利id  单位
                List<Long> needArchivesCom = new ArrayList<>();
                if (archivesCom != null) {
                    archivesCom.forEach((id, value) -> {
                        if (fundCom.containsKey(Long.valueOf(id))) {
                            needArchivesCom.add(Long.valueOf(id));
                        }
                    });
                }
                //判断核算周期、核算月、福利起始缴纳月的关系
                checkCycleSettingWithStartMonth(fundCom, billMonth, fundPO.getFundStartTime());

                List<BigDecimal> fundComList = new ArrayList<>();
                Map<String, String> fundComJsonMap = new HashMap<>();
                HashMap<String, String> finalArchivesCom = archivesCom;
                needArchivesCom.stream().forEach(e -> {
                    InsuranceSchemeDetailPO po = fundCom.get(e);
                    BigDecimal paymentProportion = new BigDecimal(StringUtils.isBlank(po.getPaymentProportion()) ? "0" : po.getPaymentProportion()).divide(new BigDecimal("100"));
                    BigDecimal paymentNum = new BigDecimal((ObjectUtil.isEmpty(finalArchivesCom) || StringUtils.isBlank(finalArchivesCom.get(String.valueOf(e)))) ? "0" : finalArchivesCom.get(String.valueOf(e)));
                    BigDecimal fixedCost = StringUtils.isBlank(po.getFixedCost()) ? new BigDecimal("0") : new BigDecimal(po.getFixedCost());
                    Integer newScale = po.getValidNum() == null ? 2 : po.getValidNum();
//                    BigDecimal result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    BigDecimal result = new BigDecimal("0");
                    if (Objects.equals(po.getPaymentCycle(), 1)) {
                        int monthValue = 1;
                        for (int i = monthIndex - 1; i >= 0; i--) {
                            String cycleValue = po.getCycleSetting().charAt(i) + "";
                            if (Integer.parseInt(cycleValue) == 1) {
                                break;
                            }
                            monthValue++;
                        }
                        if (po.getAccountType() == 1) {
                            paymentNum = paymentNum.multiply(new BigDecimal(monthValue));
                            fixedCost = fixedCost.multiply(new BigDecimal(monthValue));
                            result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                        } else {
                            for (int i = 0; i < monthValue; i++) {
                                result = result.add(SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost)));
                            }
                        }
                    } else {
                        result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    }

                    fundComJsonMap.put(String.valueOf(e), result.toPlainString());
                    fundComList.add(result);
                });
                insuranceAccountDetailPO.setFundComJson(JSON.toJSONString(fundComJsonMap));
                BigDecimal fundComSum = new BigDecimal("0");
                for (BigDecimal bigDecimal : fundComList) {
                    fundComSum = fundComSum.add(bigDecimal);
                }
                insuranceAccountDetailPO.setFundComSum(fundComSum.toPlainString());

            }
        }
        return insuranceAccountDetailPO;
    }

    public InsuranceAccountDetailPO accountSocial(InsuranceAccountDetailPO insuranceAccountDetailPO, InsuranceArchivesAccountPO accountPO, String billMonth) {
        boolean welBaseDiffSign = siArchivesBiz.isDiffWelBase();
        if (accountPO.getSocial() != null) {
            InsuranceArchivesSocialSchemePO socialPO = accountPO.getSocial();
            insuranceAccountDetailPO.setSocialPayOrg(socialPO.getPaymentOrganization());
            insuranceAccountDetailPO.setSocialAccount(socialPO.getSocialAccount());
            insuranceAccountDetailPO.setSocialSchemeId(socialPO.getSocialSchemeId());
            insuranceAccountDetailPO.setSocialPaymentBaseString(socialPO.getSocialPaymentBaseString());
            insuranceAccountDetailPO.setSocialPaymentComBaseString(socialPO.getSocialPaymentComBaseString());
            //判断是否在起始缴纳月和最后缴纳月之间
            Boolean inDataRange = SalaryDateUtil.monthInRange(billMonth, socialPO.getSocialStartTime(), socialPO.getSocialEndTime());
            if ((Objects.equals(NonPaymentEnum.YES.getValue(), socialPO.getNonPayment()) || socialPO.getNonPayment() == null) && socialPO.getSocialSchemeId() != null && inDataRange) {
                List<InsuranceSchemeDetailPO> detailPOS = getInsuranceSchemeDetailMapper().queryListBySchemeId(socialPO.getSocialSchemeId());
                encryptUtil.decryptList(detailPOS, InsuranceSchemeDetailPO.class);
                //方案中包含的需要缴纳社保的个人福利
                int monthIndex = Integer.parseInt(billMonth.split("-")[1]) - 1;
                Map<Long, InsuranceSchemeDetailPO> schemeperson = detailPOS.stream()
                        .filter(item ->
                                Objects.equals(IsPaymentEnum.YES.getValue(), item.getIsPayment()) &&
                                        Objects.equals(item.getPaymentScope(), PaymentScopeEnum.SCOPE_PERSON.getValue()) &&
                                        (item.getPaymentCycle() == null || item.getPaymentCycle() == 0 || (item.getPaymentCycle() == 1 && String.valueOf(item.getCycleSetting().charAt(monthIndex)).equals("1")))
                        )
                        .collect(
                                Collectors.toMap(InsuranceSchemeDetailPO::getInsuranceId, Function.identity()));
                //档案中包含的基数信息
                HashMap<String, String> archivesPerson = JSON.parseObject(socialPO.getSocialPaymentBaseString(), new HashMap<String, String>().getClass());
                //需要核算社保的福利id  个人
                List<Long> needArchivesPerson = new ArrayList<>();
                if (archivesPerson != null) {
                    archivesPerson.forEach((id, value) -> {
                        if (schemeperson.containsKey(Long.valueOf(id))) {
                            needArchivesPerson.add(Long.valueOf(id));
                        }
                    });
                }
                //判断核算周期、核算月、福利起始缴纳月的关系
                checkCycleSettingWithStartMonth(schemeperson, billMonth, socialPO.getSocialStartTime());

                List<BigDecimal> socialPer = new ArrayList<>();
                Map<String, String> socialPerJsonMap = new HashMap<>();
                needArchivesPerson.forEach(e -> {
                    InsuranceSchemeDetailPO po = schemeperson.get(e);
                    BigDecimal paymentProportion = new BigDecimal(StringUtils.isBlank(po.getPaymentProportion()) ? "0" : po.getPaymentProportion()).divide(new BigDecimal("100"));
                    BigDecimal paymentNum = new BigDecimal((ObjectUtil.isEmpty(archivesPerson) || StringUtils.isBlank(archivesPerson.get(String.valueOf(e)))) ? "0" : archivesPerson.get(String.valueOf(e)));
                    BigDecimal fixedCost = StringUtils.isBlank(po.getFixedCost()) ? new BigDecimal("0") : new BigDecimal(po.getFixedCost());
                    Integer newScale = po.getValidNum() == null ? 2 : po.getValidNum();
//                    BigDecimal result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    BigDecimal result = new BigDecimal("0");
                    if (Objects.equals(po.getPaymentCycle(), 1)) {
                        int monthValue = 1;
                        for (int i = monthIndex - 1; i >= 0; i--) {
                            String cycleValue = po.getCycleSetting().charAt(i) + "";
                            if (Integer.parseInt(cycleValue) == 1) {
                                break;
                            }
                            monthValue++;
                        }
                        if (po.getAccountType() == 1) {
                            paymentNum = paymentNum.multiply(new BigDecimal(monthValue));
                            fixedCost = fixedCost.multiply(new BigDecimal(monthValue));
                            result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                        } else {
                            for (int i = 0; i < monthValue; i++) {
                                result = result.add(SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost)));
                            }
                        }
                    } else {
                        result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    }

                    socialPerJsonMap.put(String.valueOf(e), result.toPlainString());
                    socialPer.add(result);
                });
                insuranceAccountDetailPO.setSocialPerJson(JSON.toJSONString(socialPerJsonMap));
                BigDecimal socialPerSum = new BigDecimal("0");
                for (BigDecimal bigDecimal : socialPer) {
                    socialPerSum = socialPerSum.add(bigDecimal);
                }
                insuranceAccountDetailPO.setSocialPerSum(socialPerSum.toPlainString());

                //方案中包含的需要缴纳社保的单位福利
                Map<Long, InsuranceSchemeDetailPO> schemeCom = detailPOS.stream()
                        .filter(item -> Objects.equals(IsPaymentEnum.YES.getValue(), item.getIsPayment()) && Objects.equals(item.getPaymentScope(), PaymentScopeEnum.SCOPE_COMPANY.getValue()) &&
                                (item.getPaymentCycle() == null || item.getPaymentCycle() == 0 || (item.getPaymentCycle() == 1 && String.valueOf(item.getCycleSetting().charAt(monthIndex)).equals("1"))))
                        .collect(
                                Collectors.toMap(InsuranceSchemeDetailPO::getInsuranceId, Function.identity()));
                //档案中包含的基数信息
//                HashMap<String, String> archivesCom = JSON.parseObject(socialPO.getSocialPaymentBaseString(), new HashMap<String, String>().getClass());
                HashMap<String, String> archivesCom = new HashMap<>();
                if (welBaseDiffSign) {
                    archivesCom = JSON.parseObject(socialPO.getSocialPaymentComBaseString(), new HashMap<String, String>().getClass());
                } else {
                    archivesCom = JSON.parseObject(socialPO.getSocialPaymentBaseString(), new HashMap<String, String>().getClass());
                }
                //需要核算社保的福利id  单位
                List<Long> needArchivesCom = new ArrayList<>();
                if (archivesCom != null) {
                    archivesCom.forEach((id, value) -> {
                        if (schemeCom.containsKey(Long.valueOf(id))) {
                            needArchivesCom.add(Long.valueOf(id));
                        }
                    });
                }
                //判断核算周期、核算月、福利起始缴纳月的关系
                checkCycleSettingWithStartMonth(schemeCom, billMonth, socialPO.getSocialStartTime());

                List<BigDecimal> socialCom = new ArrayList<>();
                Map<String, String> sociaComJsonMap = new HashMap<>();
                HashMap<String, String> finalArchivesCom = archivesCom;
                needArchivesCom.stream().forEach(e -> {
                    InsuranceSchemeDetailPO po = schemeCom.get(e);
                    BigDecimal paymentProportion = new BigDecimal(StringUtils.isBlank(po.getPaymentProportion()) ? "0" : po.getPaymentProportion()).divide(new BigDecimal("100"));
                    BigDecimal paymentNum = new BigDecimal((ObjectUtil.isEmpty(finalArchivesCom) || StringUtils.isBlank(finalArchivesCom.get(String.valueOf(e)))) ? "0" : finalArchivesCom.get(String.valueOf(e)));
                    BigDecimal fixedCost = StringUtils.isBlank(po.getFixedCost()) ? new BigDecimal("0") : new BigDecimal(po.getFixedCost());
                    Integer newScale = po.getValidNum() == null ? 2 : po.getValidNum();
//                    BigDecimal result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    BigDecimal result = new BigDecimal("0");
                    if (Objects.equals(po.getPaymentCycle(), 1)) {
                        int monthValue = 1;
                        for (int i = monthIndex - 1; i >= 0; i--) {
                            String cycleValue = po.getCycleSetting().charAt(i) + "";
                            if (Integer.parseInt(cycleValue) == 1) {
                                break;
                            }
                            monthValue++;
                        }
                        if (po.getAccountType() == 1) {
                            paymentNum = paymentNum.multiply(new BigDecimal(monthValue));
                            fixedCost = fixedCost.multiply(new BigDecimal(monthValue));
                            result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                        } else {
                            for (int i = 0; i < monthValue; i++) {
                                result = result.add(SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost)));
                            }
                        }
                    } else {
                        result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    }

                    sociaComJsonMap.put(String.valueOf(e), result.toPlainString());
                    socialCom.add(result);

                });
                insuranceAccountDetailPO.setSocialComJson(JSON.toJSONString(sociaComJsonMap));
                BigDecimal socialComSum = new BigDecimal("0");
                for (BigDecimal decimal : socialCom) {
                    socialComSum = socialComSum.add(decimal);
                }
                insuranceAccountDetailPO.setSocialComSum(socialComSum.toPlainString());
            }

        }
        return insuranceAccountDetailPO;
    }

    public InsuranceAccountDetailPO accountEndowmentInsurance(InsuranceAccountDetailPO insuranceAccountDetailPO, InsuranceArchivesAccountPO accountPO, List<Long> categoryIds, String billMonth) {
        if (accountPO.getSocial() != null) {
            InsuranceArchivesSocialSchemePO socialPO = accountPO.getSocial();
            insuranceAccountDetailPO.setSocialPayOrg(socialPO.getPaymentOrganization());
            insuranceAccountDetailPO.setSocialAccount(socialPO.getSocialAccount());
            insuranceAccountDetailPO.setSocialSchemeId(socialPO.getSocialSchemeId());
            insuranceAccountDetailPO.setSocialPaymentBaseString(socialPO.getSocialPaymentBaseString());
            insuranceAccountDetailPO.setSocialPaymentComBaseString(socialPO.getSocialPaymentComBaseString());
            //判断是否在起始缴纳月和最后缴纳月之间
            Boolean inDataRange = SalaryDateUtil.monthInRange(billMonth, socialPO.getSocialStartTime(), socialPO.getSocialEndTime());

            if ((Objects.equals(NonPaymentEnum.YES.getValue(), socialPO.getNonPayment()) || socialPO.getNonPayment() == null) && socialPO.getSocialSchemeId() != null && inDataRange) {
                List<InsuranceSchemeDetailPO> detailPOS = getInsuranceSchemeDetailMapper().queryListBySchemeId(socialPO.getSocialSchemeId());
                encryptUtil.decryptList(detailPOS, InsuranceSchemeDetailPO.class);
                //方案中包含的需要缴纳社保的个人福利
                int monthIndex = Integer.parseInt(billMonth.split("-")[1]) - 1;
                Map<Long, InsuranceSchemeDetailPO> schemeperson = detailPOS.stream()
                        .filter(item -> Objects.equals(IsPaymentEnum.YES.getValue(), item.getIsPayment())
                                && Objects.equals(item.getPaymentScope(), PaymentScopeEnum.SCOPE_PERSON.getValue())
                                && (item.getPaymentCycle() == null || item.getPaymentCycle() == 0 || (item.getPaymentCycle() == 1 && String.valueOf(item.getCycleSetting().charAt(monthIndex)).equals("1"))))
                        .collect(
                                Collectors.toMap(InsuranceSchemeDetailPO::getInsuranceId, Function.identity()));
                //档案中包含的基数信息
                HashMap<String, String> archivesPerson = JSON.parseObject(socialPO.getSocialPaymentBaseString(), new HashMap<String, String>().getClass());
                //需要核算社保的福利id  个人
                List<Long> needArchivesPerson = new ArrayList<>();
                if (archivesPerson != null) {
                    categoryIds.forEach(item -> {
                        if (archivesPerson.containsKey(String.valueOf(item)) && schemeperson.containsKey(item)) {
                            if (StringUtils.isNotBlank(archivesPerson.get(String.valueOf(item)))) {
                                needArchivesPerson.add(item);
                            }

                        }
                    });
                }
                //判断核算周期、核算月、福利起始缴纳月的关系
                checkCycleSettingWithStartMonth(schemeperson, billMonth, socialPO.getSocialStartTime());

                List<BigDecimal> socialPer = new ArrayList<>();
                Map<String, String> socialPerJsonMap = new HashMap<>();
                needArchivesPerson.forEach(e -> {
                    InsuranceSchemeDetailPO po = schemeperson.get(e);
                    BigDecimal paymentProportion = new BigDecimal(po.getPaymentProportion()).divide(new BigDecimal("100"));
//                    BigDecimal paymentNum = new BigDecimal(archivesPerson.get(String.valueOf(e)));
                    BigDecimal paymentNum = new BigDecimal((ObjectUtil.isEmpty(archivesPerson) || StringUtils.isBlank(archivesPerson.get(String.valueOf(e)))) ? "0" : archivesPerson.get(String.valueOf(e)));
                    BigDecimal fixedCost = StringUtils.isBlank(po.getFixedCost()) ? new BigDecimal("0") : new BigDecimal(po.getFixedCost());
                    Integer newScale = po.getValidNum() == null ? 2 : po.getValidNum();
//                    BigDecimal result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                                        BigDecimal result = new BigDecimal("0");
                    if (Objects.equals(po.getPaymentCycle(), 1)) {
                        int monthValue = 1;
                        for (int i = monthIndex - 1; i >= 0; i--) {
                            String cycleValue = po.getCycleSetting().charAt(i) + "";
                            if (Integer.parseInt(cycleValue) == 1) {
                                break;
                            }
                            monthValue++;
                        }
                        if (po.getAccountType() == 1) {
                            paymentNum = paymentNum.multiply(new BigDecimal(monthValue));
                            fixedCost = fixedCost.multiply(new BigDecimal(monthValue));
                            result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                        } else {
                            for (int i = 0; i < monthValue; i++) {
                                result = result.add(SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost)));
                            }
                        }
                    } else {
                        result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    }
                    socialPerJsonMap.put(String.valueOf(e), result.toPlainString());
                    socialPer.add(result);
                });
                insuranceAccountDetailPO.setSocialPerJson(JSON.toJSONString(socialPerJsonMap));
                BigDecimal socialPerSum = new BigDecimal("0");
                for (BigDecimal bigDecimal : socialPer) {
                    socialPerSum = socialPerSum.add(bigDecimal);
                }
                insuranceAccountDetailPO.setSocialPerSum(socialPerSum.toPlainString());

                //方案中包含的需要缴纳社保的单位福利
                Map<Long, InsuranceSchemeDetailPO> schemeCom = detailPOS.stream()
                        .filter(item -> Objects.equals(IsPaymentEnum.YES.getValue(), item.getIsPayment()) && Objects.equals(item.getPaymentScope(), PaymentScopeEnum.SCOPE_COMPANY.getValue()) &&
                                (item.getPaymentCycle() == null || item.getPaymentCycle() == 0 || (item.getPaymentCycle() == 1 && String.valueOf(item.getCycleSetting().charAt(monthIndex)).equals("1"))))
                        .collect(
                                Collectors.toMap(InsuranceSchemeDetailPO::getInsuranceId, Function.identity()));
                //档案中包含的基数信息
                HashMap<String, String> archivesCom = JSON.parseObject(socialPO.getSocialPaymentBaseString(), new HashMap<String, String>().getClass());
                //需要核算社保的福利id  单位
                List<Long> needArchivesCom = new ArrayList<>();
                if (archivesCom != null) {
                    categoryIds.forEach(item -> {
                        if (archivesCom.containsKey(String.valueOf(item)) && schemeCom.containsKey(item)) {
                            if (StringUtils.isNotBlank(archivesCom.get(String.valueOf(item)))) {
                                needArchivesCom.add(item);
                            }

                        }
                    });
                    //判断核算周期、核算月、福利起始缴纳月的关系
                    checkCycleSettingWithStartMonth(schemeCom, billMonth, socialPO.getSocialStartTime());

//                    archivesCom.forEach((id, value) -> {
//                        if (schemeCom.containsKey(Long.valueOf(id))) {
//                            needArchivesCom.add(Long.valueOf(id));
//                        }
//                    });
                }

                List<BigDecimal> socialCom = new ArrayList<>();
                Map<String, String> sociaComJsonMap = new HashMap<>();
                needArchivesCom.forEach(e -> {
                    InsuranceSchemeDetailPO po = schemeCom.get(e);
                    BigDecimal paymentProportion = new BigDecimal(po.getPaymentProportion()).divide(new BigDecimal("100"));
//                    BigDecimal paymentNum = SalaryEntityUtil.string2BigDecimalDefault0(archivesCom.get(String.valueOf(e)));
                    BigDecimal paymentNum = new BigDecimal((ObjectUtil.isEmpty(archivesCom) || StringUtils.isBlank(archivesCom.get(String.valueOf(e)))) ? "0" : archivesCom.get(String.valueOf(e)));
                    BigDecimal fixedCost = StringUtils.isBlank(po.getFixedCost()) ? new BigDecimal("0") : new BigDecimal(po.getFixedCost());
                    Integer newScale = po.getValidNum() == null ? 2 : po.getValidNum();
//                    BigDecimal result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    BigDecimal result = new BigDecimal("0");
                    if (Objects.equals(po.getPaymentCycle(), 1)) {
                        int monthValue = 1;
                        for (int i = monthIndex - 1; i >= 0; i--) {
                            String cycleValue = po.getCycleSetting().charAt(i) + "";
                            if (Integer.parseInt(cycleValue) == 1) {
                                break;
                            }
                            monthValue++;
                        }
                        if (po.getAccountType() == 1) {
                            paymentNum = paymentNum.multiply(new BigDecimal(monthValue));
                            fixedCost = fixedCost.multiply(new BigDecimal(monthValue));
                            result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                        } else {
                            for (int i = 0; i < monthValue; i++) {
                                result = result.add(SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost)));
                            }
                        }
                    } else {
                        result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    }

                    sociaComJsonMap.put(String.valueOf(e), result.toPlainString());
                    socialCom.add(result);

                });
                insuranceAccountDetailPO.setSocialComJson(JSON.toJSONString(sociaComJsonMap));
                BigDecimal socialComSum = new BigDecimal("0");
                for (BigDecimal decimal : socialCom) {
                    socialComSum = socialComSum.add(decimal);
                }
                insuranceAccountDetailPO.setSocialComSum(socialComSum.toPlainString());
            }
        }
        return insuranceAccountDetailPO;
    }


    private List<List<InsuranceAccountDetailPO>> splitDetailList(List<InsuranceAccountDetailPO> list, int groupSize) {
        int length = list.size();
        // 计算可以分成多少组
        int num = (length + groupSize - 1) / groupSize;
        List<List<InsuranceAccountDetailPO>> newList = new ArrayList<>(num);
        for (int i = 0; i < num; i++) {
            // 开始位置
            int fromIndex = i * groupSize;
            // 结束位置
            int toIndex = (i + 1) * groupSize < length ? (i + 1) * groupSize : length;
            newList.add(list.subList(fromIndex, toIndex));
        }
        return newList;
    }

    public void batchSaveSupplementAccount(List<InsuranceAccountDetailPO> pos, String billMonth, String tenantKey) {
        if (CollectionUtils.isEmpty(pos)) {
            return;
        }
        batchSaveAccountInspectDetail(pos, billMonth, tenantKey);
        getInsuranceAccountDetailMapper().batchDelSupplementAccountDetails(pos);
        encryptUtil.encryptList(pos, InsuranceAccountDetailPO.class);
        List<List<InsuranceAccountDetailPO>> lists = splitDetailList(pos, 20);
        lists.forEach(subList -> {
            getInsuranceAccountDetailMapper().batchSaveAccountDetails(subList);
        });
        //删除日志
//        pos.stream().forEach(item -> {
//            LoggerContext insuranceSchemeContext = new LoggerContext();
//            insuranceSchemeContext.setTargetId(String.valueOf(item.getId()));
//            insuranceSchemeContext.setTargetName(String.valueOf(item.getEmployeeId()));
//            insuranceSchemeContext.setOperateType(OperateTypeEnum.DELETE.getValue());
//            insuranceSchemeContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(100448, "删除核算记录"));
//            insuranceSchemeContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(100448, "删除核算记录"));
//            insuranceSchemeContext.setNewValues(item);
//            siAccountLoggerTemplate.write(insuranceSchemeContext);
//        });
        //插入日志
//        pos.stream().forEach(item -> {
//            LoggerContext insuranceSchemeContext = new LoggerContext();
//            insuranceSchemeContext.setTargetId(String.valueOf(item.getId()));
//            insuranceSchemeContext.setTargetName(String.valueOf(item.getEmployeeId()));
//            insuranceSchemeContext.setOperateType(OperateTypeEnum.ADD.getValue());
//            insuranceSchemeContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(100494, "新建核算记录"));
//            insuranceSchemeContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(100494, "新建核算记录"));
//            insuranceSchemeContext.setNewValues(item);
//            siAccountLoggerTemplate.write(insuranceSchemeContext);
//        });
    }

    public void deleteCommonAccount(SaveCommonAccountParam param, Long employeeId, String currentUserName) {
        ValidUtil.doValidator(param);
        SalaryAssert.notEmpty(param.getIncludes(), SalaryI18nUtil.getI18nLabel(84026, "参数错误"));
        //根据id批量删除
        if (param.getIds().size() > 0) {
            getInsuranceAccountDetailMapper().batchDelAccountDetailsByIds(param.getIds());
        } else {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(0, "请勾选需要删除的数据项！"));
        }
        //记录日志
//        LoggerContext insuranceSchemeContext = new LoggerContext();
//        insuranceSchemeContext.setTargetId(String.join(",", param.getIncludes().stream().map(item -> String.valueOf(item)).collect(Collectors.toList())));
//        insuranceSchemeContext.setTargetName(param.getBillMonth());
//        insuranceSchemeContext.setOperateType(OperateTypeEnum.ADD.getValue());
//        insuranceSchemeContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(tenantKey, employeeId, 100462, "新增台账"));
//        insuranceSchemeContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(tenantKey, employeeId, 100462, "新增台账"));
//        insuranceSchemeContext.setNewValues(param);
//        siAccountLoggerTemplate.write(insuranceSchemeContext);
        updateBatchAccount(AccountParam.builder().billMonth(param.getBillMonth()).paymentOrganization(param.getPaymentOrganization()).build(), employeeId, SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY, currentUserName);
    }

    public void deleteSupplementaryAccount(List<SupplementAccountBaseParam> param, Long employeeId, String currentUserName) {
        SalaryAssert.notEmpty(param, SalaryI18nUtil.getI18nLabel(84026, "参数错误"));
        boolean valid = param.stream().anyMatch(item -> item.getEmployeeId() == null
                || StringUtils.isBlank(item.getSupplementaryMonth())
                || StringUtils.isBlank(item.getBillMonth()));
        if (valid) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(84026, "参数错误"));
        }
        getInsuranceAccountDetailMapper().batchDelSupplementDetailsByIds(param);
//        param.stream().forEach(item -> {
//            LoggerContext insuranceSchemeContext = new LoggerContext();
//            insuranceSchemeContext.setTargetName(item.getBillMonth());
//            insuranceSchemeContext.setOperateType(OperateTypeEnum.DELETE.getValue());
//            insuranceSchemeContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(tenantKey, employeeId, 100490, "删除补缴核算记录"));
//            insuranceSchemeContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(tenantKey, employeeId, 100490, "删除补缴核算记录"));
//            insuranceSchemeContext.setNewValues(item);
//            siAccountLoggerTemplate.write(insuranceSchemeContext);
//        });
        updateBatchAccount(AccountParam.builder().billMonth(param.get(0).getBillMonth()).paymentOrganization(param.get(0).getPaymentOrganization()).build(), employeeId, SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY, currentUserName);
    }

    public void file(String billMonth, Long employeeId, Long paymentOrganization) {
        // 归档前检查是否有核算异常
//        List<InsuranceAccountInspectPO> insuranceAccountInspectPOS =  getInsuranceAccountInspectMapper().getByInspectStatusAndBillMonth(InspectStatusEnum.IGNORE.getValue(),billMonth);

//        SalaryAssert.isEmpty(insuranceAccountInspectPOS, SalaryI18nUtil.getI18nLabel( 100500, "当前核算月存在核算异常数据"));
        //开始归档数据
        InsuranceAccountBatchPO insuranceAccountBatchPO = getInsuranceAccountBatchMapper().getByBillStatus(billMonth, BillStatusEnum.NOT_ARCHIVED.getValue(), paymentOrganization);
        encryptUtil.decrypt(insuranceAccountBatchPO, InsuranceAccountBatchPO.class);
        SalaryAssert.notNull(insuranceAccountBatchPO, SalaryI18nUtil.getI18nLabel(100503, "月份账单不存在"));
        SalaryAssert.isFalse(Objects.equals(insuranceAccountBatchPO.getBillStatus(), BillStatusEnum.ARCHIVED.getValue()), SalaryI18nUtil.getI18nLabel(100504, "月份账单已归档"));
        insuranceAccountBatchPO.setBillStatus(BillStatusEnum.ARCHIVED.getValue());
        encryptUtil.encrypt(insuranceAccountBatchPO, InsuranceAccountBatchPO.class);
        getInsuranceAccountBatchMapper().updateById(insuranceAccountBatchPO);
        //日志记录
//        LoggerContext insuranceSchemeContext = new LoggerContext();
//        insuranceSchemeContext.setTargetId(String.valueOf(insuranceAccountBatchPO.getId()));
//        insuranceSchemeContext.setTargetName(insuranceAccountBatchPO.getBillMonth());
//        insuranceSchemeContext.setOperateType(OperateTypeEnum.UPDATE.getValue());
//        insuranceSchemeContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(tenantKey, employeeId, 100506, "台账归档"));
//        insuranceSchemeContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(tenantKey, employeeId, 100506, "台账归档"));
//        insuranceSchemeContext.setNewValues(insuranceAccountBatchPO);
//        siAccountLoggerTemplate.write(insuranceSchemeContext);
    }


    public void accountInspect(Collection<Long> ids, String billMonth, Long employeeId, String currentUserName, Long paymentOrganization) {
        List<InsuranceAccountInspectPO> insuranceAccountInspectPOS = allInspects(ids, billMonth);
        SalaryAssert.notEmpty(insuranceAccountInspectPOS, SalaryI18nUtil.getI18nLabel(100515, "无核算数据"));
        List<InsuranceAccountInspectPO> commonInspects = insuranceAccountInspectPOS.stream()
                .filter(e -> Objects.equals(e.getPaymentStatus(), PaymentStatusEnum.COMMON.getValue()))
                .collect(Collectors.toList());
        List<InsuranceAccountInspectPO> supplementInspects = insuranceAccountInspectPOS.stream()
                .filter(e -> Objects.equals(e.getPaymentStatus(), PaymentStatusEnum.REPAIR.getValue()))
                .collect(Collectors.toList());
        //核算正常缴纳
        if (CollectionUtils.isNotEmpty(commonInspects)) {
            SaveCommonAccountParam param = new SaveCommonAccountParam();
            param.setBillMonth(billMonth);
            param.setIncludes(commonInspects.stream().map(InsuranceAccountInspectPO::getEmployeeId).collect(Collectors.toList()));
            saveCommonAccount(param, employeeId, currentUserName);
        }
        //核算补缴
        if (CollectionUtils.isNotEmpty(supplementInspects)) {
            List<SupplementAccountBaseParam> baseList = new ArrayList<>();
            supplementInspects.forEach(e -> {
                SupplementAccountBaseParam base = new SupplementAccountBaseParam();
                base.setBillMonth(billMonth);
                base.setProjects(
                        e.getSupplementaryProjects() == null ? null : Arrays.stream(e.getSupplementaryProjects().split(",")).map(Integer::valueOf).collect(Collectors.toList()));
                base.setEmployeeId(e.getEmployeeId());
                base.setSupplementaryMonth(e.getSupplementaryMonth());
                baseList.add(base);
            });
            accountSupplement(baseList, baseList.stream().map(SupplementAccountBaseParam::getEmployeeId).collect(Collectors.toList()), billMonth, employeeId, paymentOrganization);
        }
    }


    public List<InsuranceAccountInspectPO> allInspects(Collection<Long> ids, String billMonth) {
        List<InsuranceAccountInspectPO> list = getInsuranceAccountInspectMapper().getList(billMonth, InspectStatusEnum.IGNORE.getValue(), ids);

        if (CollectionUtils.isNotEmpty(list)) {
            return list;
        }
        return Collections.emptyList();
    }


    public PageInfo<InsuranceAccountViewListDTO> overView(InsuranceAccountDetailParam queryParam) {

//        SalaryPageUtil.start(queryParam.getCurrent(),queryParam.getPageSize());
        List<InsuranceAccountDetailPO> insuranceAccountDetailPOS = getInsuranceAccountDetailMapper().selectList(queryParam.getBillMonth(), StringUtil.isBlank(queryParam.getPaymentOrganization()) ? null : Long.valueOf(queryParam.getPaymentOrganization()));
        encryptUtil.decryptList(insuranceAccountDetailPOS, InsuranceAccountDetailPO.class);

        //获取扣缴义务人信息
        List<TaxAgentPO> paymentList = getTaxAgentMapper().listAll();
        SalaryAssert.notEmpty(paymentList, SalaryI18nUtil.getI18nLabel(100341, "该租户无扣缴义务人"));
        Map<Long, TaxAgentPO> paymentMap = paymentList.stream().collect(Collectors.toMap(TaxAgentPO::getId, Function.identity()));
        List<InsuranceAccountViewListDTO> insuranceAccountViewListDTOS = buildRecords(insuranceAccountDetailPOS, paymentMap);

//        List<ICategoryPO> iCategoryPOS = getICategoryMapper().listAll();
//        Page<InsuranceCategoryPO> page = FormatManager.getTablePage();
//        Page<InsuranceAccountViewListDTO> insuranceAccountViewListDTOPage = new Page<>(page.getCurrent(), insuranceAccountViewListDTOS.size(), insuranceAccountViewListDTOS.size(),
//                page.isSearchCount());

        PageInfo<InsuranceAccountViewListDTO> insuranceAccountViewListDTOPage = new PageInfo<>(insuranceAccountViewListDTOS, InsuranceAccountViewListDTO.class);
        insuranceAccountViewListDTOPage.setTotal(insuranceAccountViewListDTOS.size());
        return insuranceAccountViewListDTOPage;
    }

    public List<InsuranceAccountViewListDTO> buildRecords(List<InsuranceAccountDetailPO> list, Map<Long, TaxAgentPO> paymentMap) {
        Map<Long, InsuranceAccountViewListDTO> result = new HashMap<>();
        //根据组织分组,对社保进行统计
        Map<Long, List<InsuranceAccountDetailPO>> socialCollect = list.stream().filter(item -> item.getSocialPayOrg() != null)
                .collect(Collectors.groupingBy(InsuranceAccountDetailPO::getSocialPayOrg));
        socialCollect.forEach((k, v) -> {
            if (result.get(k) == null) {
                InsuranceAccountViewListDTO temp = new InsuranceAccountViewListDTO();
                temp.setPayOrg(paymentMap.get(k).getName());
                result.put(k, temp);
            }
            InsuranceAccountViewListDTO insuranceAccountViewListDTO = result.get(k);
            accountSocialView(insuranceAccountViewListDTO, v);
        });
        //根据组织分组，对公积金进行统计
        Map<Long, List<InsuranceAccountDetailPO>> fundCollect = list.stream().filter(item -> item.getSocialPayOrg() != null)
                .collect(Collectors.groupingBy(InsuranceAccountDetailPO::getSocialPayOrg));
        fundCollect.forEach((k, v) -> {
            if (result.get(k) == null) {
                InsuranceAccountViewListDTO temp = new InsuranceAccountViewListDTO();
                temp.setPayOrg(paymentMap.get(k).getName());
                result.put(k, temp);
            }
            InsuranceAccountViewListDTO insuranceAccountViewListDTO = result.get(k);
            accountFundView(insuranceAccountViewListDTO, v);
        });
        //根据组织分组,对其他福利进行统计
        Map<Long, List<InsuranceAccountDetailPO>> otherCollect = list.stream().filter(item -> item.getSocialPayOrg() != null)
                .collect(Collectors.groupingBy(InsuranceAccountDetailPO::getSocialPayOrg));
        otherCollect.forEach((k, v) -> {
            if (result.get(k) == null) {
                InsuranceAccountViewListDTO temp = new InsuranceAccountViewListDTO();
                temp.setPayOrg(paymentMap.get(k).getName());
                result.put(k, temp);
            }
            InsuranceAccountViewListDTO insuranceAccountViewListDTO = result.get(k);
            accountOtherView(insuranceAccountViewListDTO, v);
        });
        //对各组织进行金额合计
        List<InsuranceAccountViewListDTO> viewDTOS = new ArrayList<>();
        result.forEach((k, v) -> {
            BigDecimal socialPaySum = StringUtils.isBlank(v.getSocialPaySum()) ? new BigDecimal("0") : new BigDecimal(v.getSocialPaySum());
            BigDecimal fundPaySum = StringUtils.isBlank(v.getFundPaySum()) ? new BigDecimal("0") : new BigDecimal(v.getFundPaySum());
            BigDecimal otherPaySum = StringUtils.isBlank(v.getOtherPaySum()) ? new BigDecimal("0") : new BigDecimal(v.getOtherPaySum());
            v.setIndex(k);
            BigDecimal sum = socialPaySum.add(fundPaySum).add(otherPaySum);
            v.setSum(sum.toPlainString());
            viewDTOS.add(v);
        });
        //合计
        InsuranceAccountViewListDTO insuranceAccountViewListDTO = new InsuranceAccountViewListDTO();
        int socialNum = 0;
        int fundNum = 0;
        int otherNum = 0;
        BigDecimal socialSum = new BigDecimal("0");
        BigDecimal fundSum = new BigDecimal("0");
        BigDecimal otherSum = new BigDecimal("0");
        BigDecimal sum = new BigDecimal("0");
        for (InsuranceAccountViewListDTO item : viewDTOS) {
            if (item.getSocialNum() != null) {
                socialNum += item.getSocialNum();
            }
            if (item.getFundNum() != null) {
                fundNum += item.getFundNum();
            }
            if (item.getOtherNum() != null) {
                otherNum += item.getOtherNum();
            }
            if (StringUtils.isNotBlank(item.getSocialPaySum())) {
                socialSum = socialSum.add(new BigDecimal(item.getSocialPaySum()));
            }
            if (StringUtils.isNotBlank(item.getFundPaySum())) {
                fundSum = fundSum.add(new BigDecimal(item.getFundPaySum()));
            }
            if (StringUtils.isNotBlank(item.getOtherPaySum())) {
                otherSum = otherSum.add(new BigDecimal(item.getOtherPaySum()));
            }
            if (StringUtils.isNotBlank(item.getSum())) {
                sum = sum.add(new BigDecimal(item.getSum()));
            }
        }
        insuranceAccountViewListDTO.setSum(sum.toPlainString());
        insuranceAccountViewListDTO.setSocialPaySum(socialSum.toPlainString());
        insuranceAccountViewListDTO.setPayOrg(SalaryI18nUtil.getI18nLabel(93278, "合计"));
        insuranceAccountViewListDTO.setFundPaySum(fundSum.toPlainString());
        insuranceAccountViewListDTO.setOtherPaySum(otherSum.toPlainString());
        insuranceAccountViewListDTO.setSocialNum(socialNum);
        insuranceAccountViewListDTO.setFundNum(fundNum);
        insuranceAccountViewListDTO.setOtherNum(otherNum);
        viewDTOS.add(insuranceAccountViewListDTO);
        viewDTOS.forEach(e -> {
            e.setSocialPaySum(StringUtils.isBlank(e.getSocialPaySum()) ? "0" : e.getSocialPaySum());
            e.setSocialNum(e.getSocialNum() == null ? 0 : e.getSocialNum());
            e.setFundNum(e.getFundNum() == null ? 0 : e.getFundNum());
            e.setFundPaySum(StringUtils.isBlank(e.getFundPaySum()) ? "0" : e.getFundPaySum());
            e.setOtherPaySum(StringUtils.isBlank(e.getOtherPaySum()) ? "0" : e.getOtherPaySum());
            e.setOtherNum(e.getOtherNum() == null ? 0 : e.getOtherNum());
            e.setSum(SalaryEntityUtil.thousandthConvert(e.getSum()));
            e.setSocialPaySum(SalaryEntityUtil.thousandthConvert(e.getSocialPaySum()));
            e.setOtherPaySum(SalaryEntityUtil.thousandthConvert(e.getOtherPaySum()));
            e.setFundPaySum(SalaryEntityUtil.thousandthConvert(e.getFundPaySum()));
        });
        return viewDTOS;
    }

    public void accountOtherView(InsuranceAccountViewListDTO dto, List<InsuranceAccountDetailPO> pos) {
        int otherNum = 0;
        BigDecimal otherPaySum = new BigDecimal("0");
        for (InsuranceAccountDetailPO item : pos) {
            if (StringUtils.isNotBlank(item.getOtherSum()) && SalaryEntityUtil.string2DoubleDefault0(item.getOtherSum()) != 0.0) {
                if (!PaymentStatusEnum.BALANCE.getValue().equals(item.getPaymentStatus())) {
                    otherNum += 1;
                }
                otherPaySum = otherPaySum.add(new BigDecimal(item.getOtherSum()));
            }
        }
        dto.setOtherNum(otherNum);
        dto.setOtherPaySum(otherPaySum.toPlainString());
    }

    public void accountFundView(InsuranceAccountViewListDTO dto, List<InsuranceAccountDetailPO> pos) {
        int fundNum = 0;
        BigDecimal fundPaySum = new BigDecimal("0");
        for (InsuranceAccountDetailPO item : pos) {
            if (StringUtils.isNotBlank(item.getFundSum()) && SalaryEntityUtil.string2DoubleDefault0(item.getFundSum()) != 0.0) {
                if (!PaymentStatusEnum.BALANCE.getValue().equals(item.getPaymentStatus())) {
                    fundNum += 1;
                }
                fundPaySum = fundPaySum.add(new BigDecimal(item.getFundSum()));
            }
        }
        dto.setFundNum(fundNum);
        dto.setFundPaySum(fundPaySum.toPlainString());
    }

    public void accountSocialView(InsuranceAccountViewListDTO dto, List<InsuranceAccountDetailPO> pos) {
        int socialNum = 0;
        BigDecimal socialPaySum = new BigDecimal("0");
        for (InsuranceAccountDetailPO item : pos) {
            if (StringUtils.isNotBlank(item.getSocialSum()) &&  SalaryEntityUtil.string2DoubleDefault0(item.getSocialSum()) != 0.0 ) {
                if (!PaymentStatusEnum.BALANCE.getValue().equals(item.getPaymentStatus())) {
                    socialNum += 1;
                }
                socialPaySum = socialPaySum.add(new BigDecimal(item.getSocialSum()));
            }
        }
        dto.setSocialNum(socialNum);
        dto.setSocialPaySum(socialPaySum.toPlainString());
    }


    /**
     * 查询台账id是否已经薪资核算核算过
     *
     * @param param
     * @return
     */
    public int checkIfBusinessaccounting(InsuranceAccountBatchPO param) {
        List<SIAccountUtilDTO> list = getSIAccountUtilMapper().checkIfBusinessaccounting(param.getId());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        return (int) list.stream().filter( f -> {
            String billMonthBySob = sdf.format(convertSalaryMonthToBillMonth(f.getSalaryMonth(), f.getSocialSecurityCycleType()));
            return f.getBillmonth().equals(billMonthBySob.substring(0, 7));
        }).count();
    }

    public Date convertSalaryMonthToBillMonth(Date salaryMonth, Integer socialSecurityCycleType) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(salaryMonth);
        calendar.add(Calendar.MONTH, socialSecurityCycleType - 3);
        return calendar.getTime();
    }
    /**
     * 更新薪资台账
     *
     * @param param
     * @return
     */
    public void updateById(InsuranceAccountBatchPO param) {
        getInsuranceAccountBatchMapper().updateById(param);
    }

    /**
     * 更新福利台账
     */
    public void updateByEmployeeIdAndBillMonth(InsuranceAccountDetailPO insuranceAccountDetailPO) {
        getInsuranceAccountDetailMapper().updateByEmployeeIdAndBillMonth(insuranceAccountDetailPO);
    }

    public void accountFundByData(InsuranceAccountDetailPO insuranceAccountDetailPO, SupplementAccountBaseParam baseParam) {
        //公积金个人
        if (StringUtils.isNotBlank(baseParam.getFundPaymentPerString())) {
            List<BigDecimal> fundPer = new ArrayList<>();
            HashMap<String, String> fundPerson = JSON.parseObject(baseParam.getFundPaymentPerString(), new HashMap<String, String>().getClass());
            fundPerson.forEach((k, v) -> {
                BigDecimal result = new BigDecimal(v);
                fundPer.add(result);
            });
            insuranceAccountDetailPO.setFundPerJson(baseParam.getFundPaymentPerString());
            BigDecimal fundPerSum = new BigDecimal("0");
            for (BigDecimal bigDecimal : fundPer) {
                fundPerSum = fundPerSum.add(bigDecimal);
            }
            insuranceAccountDetailPO.setFundPerSum(fundPerSum.toPlainString());
        }
        //公积金单位
        if (StringUtils.isNotBlank(baseParam.getFundPaymentComString())) {
            List<BigDecimal> fundCom = new ArrayList<>();
            HashMap<String, String> fundComMap = JSON.parseObject(baseParam.getFundPaymentComString(), new HashMap<String, String>().getClass());
            fundComMap.forEach((k, v) -> {
                BigDecimal result = new BigDecimal(v);
                fundCom.add(result);
            });
            insuranceAccountDetailPO.setFundComJson(baseParam.getFundPaymentComString());
            BigDecimal fundComSum = new BigDecimal("0");
            for (BigDecimal bigDecimal : fundCom) {
                fundComSum = fundComSum.add(bigDecimal);
            }
            insuranceAccountDetailPO.setFundComSum(fundComSum.toPlainString());
        }
    }

    public void accountOtherByData(InsuranceAccountDetailPO insuranceAccountDetailPO, SupplementAccountBaseParam baseParam) {
        //其他福利个人
        if (StringUtils.isNotBlank(baseParam.getOtherPaymentPerString())) {
            List<BigDecimal> otherPer = new ArrayList<>();
            HashMap<String, String> otherPerMap = JSON.parseObject(baseParam.getOtherPaymentPerString(), new HashMap<String, String>().getClass());
            otherPerMap.forEach((k, v) -> {
                BigDecimal result = new BigDecimal(v);
                otherPer.add(result);
            });
            insuranceAccountDetailPO.setOtherPerJson(baseParam.getOtherPaymentPerString());
            BigDecimal otherPerSum = new BigDecimal("0");
            for (BigDecimal bigDecimal : otherPer) {
                otherPerSum = otherPerSum.add(bigDecimal);
            }
            insuranceAccountDetailPO.setOtherPerSum(otherPerSum.toPlainString());
        }
        //其他福利单位
        if (StringUtils.isNotBlank(baseParam.getOtherPaymentComString())) {
            List<BigDecimal> otherCom = new ArrayList<>();
            HashMap<String, String> otherComMap = JSON.parseObject(baseParam.getOtherPaymentComString(), new HashMap<String, String>().getClass());
            otherComMap.forEach((k, v) -> {
                BigDecimal result = new BigDecimal(v);
                otherCom.add(result);
            });
            insuranceAccountDetailPO.setOtherComJson(baseParam.getOtherPaymentComString());
            BigDecimal otherComSum = new BigDecimal("0");
            for (BigDecimal bigDecimal : otherCom) {
                otherComSum = otherComSum.add(bigDecimal);
            }
            insuranceAccountDetailPO.setOtherComSum(otherComSum.toPlainString());
        }
    }

    public void accountSocialByData(InsuranceAccountDetailPO insuranceAccountDetailPO, SupplementAccountBaseParam baseParam) {
        //社保个人
        if (StringUtils.isNotBlank(baseParam.getSocialPaymentPerString())) {
            List<BigDecimal> socialPer = new ArrayList<>();
            HashMap<String, String> archivesPerson = JSON.parseObject(baseParam.getSocialPaymentPerString(), new HashMap<String, String>().getClass());
            archivesPerson.forEach((k, v) -> {
                BigDecimal result = new BigDecimal(v);
                socialPer.add(result);
            });
            insuranceAccountDetailPO.setSocialPerJson(baseParam.getSocialPaymentPerString());
            BigDecimal socialPerSum = new BigDecimal("0");
            for (BigDecimal bigDecimal : socialPer) {
                socialPerSum = socialPerSum.add(bigDecimal);
            }
            insuranceAccountDetailPO.setSocialPerSum(socialPerSum.toPlainString());
        }
        //社保单位
        if (StringUtils.isNotBlank(baseParam.getSocialPaymentComString())) {
            List<BigDecimal> socialCom = new ArrayList<>();
            HashMap<String, String> archivesCom = JSON.parseObject(baseParam.getSocialPaymentComString(), new HashMap<String, String>().getClass());
            archivesCom.forEach((k, v) -> {
                BigDecimal result = new BigDecimal(v);
                socialCom.add(result);
            });
            insuranceAccountDetailPO.setSocialComJson(baseParam.getSocialPaymentComString());
            BigDecimal socialComSum = new BigDecimal("0");
            for (BigDecimal bigDecimal : socialCom) {
                socialComSum = socialComSum.add(bigDecimal);
            }
            insuranceAccountDetailPO.setSocialComSum(socialComSum.toPlainString());
        }
    }

    public void accountEndowmentInsuranceByData(InsuranceAccountDetailPO insuranceAccountDetailPO, SupplementAccountBaseParam baseParam, List<Long> ids) {
        //社保个人
        if (StringUtils.isNotBlank(baseParam.getSocialPaymentPerString())) {
            List<BigDecimal> socialPer = new ArrayList<>();
            HashMap<String, String> archivesPerson = JSON.parseObject(baseParam.getSocialPaymentPerString(), new HashMap<String, String>().getClass());
            HashMap<String, String> socialPerson = new HashMap<>();
            archivesPerson.forEach((k, v) -> {
                if (ids.contains(Long.valueOf(k))) {
                    socialPerson.put(k, v);
                    BigDecimal result = new BigDecimal(v);
                    socialPer.add(result);
                }

            });
            insuranceAccountDetailPO.setSocialPerJson(JSON.toJSONString(socialPerson));
            BigDecimal socialPerSum = new BigDecimal("0");
            for (BigDecimal bigDecimal : socialPer) {
                socialPerSum = socialPerSum.add(bigDecimal);
            }
            insuranceAccountDetailPO.setSocialPerSum(socialPerSum.toPlainString());
        }
        //社保单位
        if (StringUtils.isNotBlank(baseParam.getSocialPaymentComString())) {
            List<BigDecimal> socialCom = new ArrayList<>();
            HashMap<String, String> archivesCom = JSON.parseObject(baseParam.getSocialPaymentComString(), new HashMap<String, String>().getClass());
            HashMap<String, String> socialComMap = new HashMap<>();
            archivesCom.forEach((k, v) -> {
                if (ids.contains(Long.valueOf(k))) {
                    socialComMap.put(k, v);
                    BigDecimal result = new BigDecimal(v);
                    socialCom.add(result);
                }
            });
            insuranceAccountDetailPO.setSocialComJson(JSON.toJSONString(socialComMap));
            BigDecimal socialComSum = new BigDecimal("0");
            for (BigDecimal bigDecimal : socialCom) {
                socialComSum = socialComSum.add(bigDecimal);
            }
            insuranceAccountDetailPO.setSocialComSum(socialComSum.toPlainString());
        }
    }
}
